A high level authority key identifier.
Inheritance: Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier
Exemple #1
0
        private void checkCrlCreation3()
        {
            IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
            kpGen.Init(
                new RsaKeyGenerationParameters(
                    BigInteger.ValueOf(0x10001), new SecureRandom(), 768, 25));

            X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
            DateTime now = DateTime.UtcNow;
            AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();

            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));

            crlGen.SetThisUpdate(now);
            crlGen.SetNextUpdate(now.AddSeconds(100));
            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");

            IList extOids = new ArrayList();
            IList extValues = new ArrayList();

            CrlReason crlReason = new CrlReason(CrlReason.PrivilegeWithdrawn);

            try
            {
                extOids.Add(X509Extensions.ReasonCode);
                extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
            }
            catch (IOException e)
            {
                throw new ArgumentException("error encoding reason: " + e);
            }

            X509Extensions entryExtensions = new X509Extensions(extOids, extValues);

            crlGen.AddCrlEntry(BigInteger.One, now, entryExtensions);

            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));

            X509Crl crl = crlGen.Generate(pair.Private);

            if (!crl.IssuerDN.Equivalent(new X509Name("CN=Test CA"), true))
            {
                Fail("failed CRL issuer test");
            }

            Asn1OctetString authExt = crl.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);

            if (authExt == null)
            {
                Fail("failed to find CRL extension");
            }

            AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);

            X509CrlEntry entry = crl.GetRevokedCertificate(BigInteger.One);

            if (entry == null)
            {
                Fail("failed to find CRL entry");
            }

            if (!entry.SerialNumber.Equals(BigInteger.One))
            {
                Fail("CRL cert serial number does not match");
            }

            if (!entry.HasExtensions)
            {
                Fail("CRL entry extension not found");
            }

            Asn1OctetString ext = entry.GetExtensionValue(X509Extensions.ReasonCode);

            if (ext != null)
            {
                DerEnumerated reasonCode = (DerEnumerated)X509ExtensionUtilities.FromExtensionValue(ext);

                if (reasonCode.Value.IntValue != CrlReason.PrivilegeWithdrawn)
                {
                    Fail("CRL entry reasonCode wrong");
                }
            }
            else
            {
                Fail("CRL entry reasonCode not found");
            }

            //
            // check loading of existing CRL
            //
            crlGen = new X509V2CrlGenerator();
            now = DateTime.UtcNow;

            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));

            crlGen.SetThisUpdate(now);
            crlGen.SetNextUpdate(now.AddSeconds(100));
            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");

            crlGen.AddCrl(crl);

            crlGen.AddCrlEntry(BigInteger.Two, now, entryExtensions);

            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));

            X509Crl newCrl = crlGen.Generate(pair.Private);

            int count = 0;
            bool oneFound = false;
            bool twoFound = false;

            foreach (X509CrlEntry crlEnt in newCrl.GetRevokedCertificates())
            {
                if (crlEnt.SerialNumber.IntValue == 1)
                {
                    oneFound = true;
                }
                else if (crlEnt.SerialNumber.IntValue == 2)
                {
                    twoFound = true;
                }

                count++;
            }

            if (count != 2)
            {
                Fail("wrong number of CRLs found");
            }

            if (!oneFound || !twoFound)
            {
                Fail("wrong CRLs found in copied list");
            }

            //
            // check factory read back
            //
            X509Crl readCrl = new X509CrlParser().ReadCrl(newCrl.GetEncoded());

            if (readCrl == null)
            {
                Fail("crl not returned!");
            }

//			ICollection col = cFact.generateCRLs(new ByteArrayInputStream(newCrl.getEncoded()));
            ICollection col = new X509CrlParser().ReadCrls(newCrl.GetEncoded());

            if (col.Count != 1)
            {
                Fail("wrong number of CRLs found in collection");
            }
        }
        /// <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 void GenerateCertificate(string subjectName, DateTime expireOnUtc, byte[] issuingCertificate, string issuingCertificatePassword, out string password, out byte[] cerData, out byte[] pkcs12Data)
        {

            AsymmetricKeyParameter caPrivateKey;
            var caCert = ReadCertificateFromBytes(issuingCertificate, issuingCertificatePassword, out caPrivateKey);

            var caAuth = new AuthorityKeyIdentifierStructure(caCert);
            var authKeyId = new AuthorityKeyIdentifier(caAuth.GetKeyIdentifier());

            // Generating Random Numbers
            var randomGenerator = new CryptoApiRandomGenerator();
            var random = new SecureRandom(randomGenerator);

            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-()#$%^&@+=!";
            var rnd = new Random();
            var result = new string(
                Enumerable.Repeat(chars, 15)
                          .Select(s => s[rnd.Next(s.Length)])
                          .ToArray());
            password = result;

            var gen = new X509V3CertificateGenerator();
            var certName = new X509Name("CN=" + subjectName);
            var serialNo = BigInteger.ProbablePrime(120, random);
            gen.SetSerialNumber(serialNo);
            gen.SetSubjectDN(certName);
            gen.SetIssuerDN(caCert.IssuerDN);

            // gen.SetIssuerUniqueID(caCert.IssuerUniqueID.GetBytes())

            gen.SetNotAfter(expireOnUtc);
            gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
            gen.SetSignatureAlgorithm("SHA256WithRSA"); //("MD5WithRSA");

            var kpgen = new RsaKeyPairGenerator();
            kpgen.Init(new KeyGenerationParameters(random, 2048)); // new SecureRandom(new CryptoApiRandomGenerator()), 2048));
            var subjectKeyPair = kpgen.GenerateKeyPair();
            gen.SetPublicKey(subjectKeyPair.Public);

            //gen.AddExtension(
            //    X509Extensions.ExtendedKeyUsage.Id,
            //    false,
            //    new ExtendedKeyUsage(new KeyPurposeID[] { KeyPurposeID.IdKPClientAuth, KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPCodeSigning }));

            //1.3.6.1.5.5.7.3.1 = server authentication
            //1.3.6.1.5.5.7.3.2 = client authentication
            //1.3.6.1.5.5.7.3.3 = code signing

            var certificate = gen.Generate(caPrivateKey);

            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

            // merge into X509Certificate2
            var x509 = X509CertificateHelper.GetCertificate(certificate.GetEncoded(), null, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);
            var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKey.GetDerEncoded());
            if (seq.Count != 9)
            {
                throw new PemException("Malformed sequence in RSA private key.");
            }

            var rsa = new RsaPrivateKeyStructure(seq);
            RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
                rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

            RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rsaparams);
            CspParameters cspParameters = new CspParameters();
            cspParameters.KeyContainerName = Guid.NewGuid().ToString(); // "MyKeyContainer";
            RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(2048, cspParameters);
            rsaKey.ImportParameters(rsaParameters);

            x509.PrivateKey = rsaKey; 
            cerData = x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert);
            pkcs12Data = x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, password);
        }
Exemple #3
0
        private void checkCrlCreation2()
        {
            IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
            kpGen.Init(
                new RsaKeyGenerationParameters(
                    BigInteger.ValueOf(0x10001), new SecureRandom(), 768, 25));

            X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
            DateTime now = DateTime.UtcNow;
            AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();

            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));

            crlGen.SetThisUpdate(now);
            crlGen.SetNextUpdate(now.AddSeconds(100));
            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");

            IList extOids = new ArrayList();
            IList extValues = new ArrayList();

            CrlReason crlReason = new CrlReason(CrlReason.PrivilegeWithdrawn);

            try
            {
                extOids.Add(X509Extensions.ReasonCode);
                extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
            }
            catch (IOException e)
            {
                throw new ArgumentException("error encoding reason: " + e);
            }

            X509Extensions entryExtensions = new X509Extensions(extOids, extValues);

            crlGen.AddCrlEntry(BigInteger.One, now, entryExtensions);

            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));

            X509Crl crl = crlGen.Generate(pair.Private);

            if (!crl.IssuerDN.Equivalent(new X509Name("CN=Test CA"), true))
            {
                Fail("failed CRL issuer test");
            }

            Asn1OctetString authExt = crl.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);

            if (authExt == null)
            {
                Fail("failed to find CRL extension");
            }

            AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);

            X509CrlEntry entry = crl.GetRevokedCertificate(BigInteger.One);

            if (entry == null)
            {
                Fail("failed to find CRL entry");
            }

            if (!entry.SerialNumber.Equals(BigInteger.One))
            {
                Fail("CRL cert serial number does not match");
            }

            if (!entry.HasExtensions)
            {
                Fail("CRL entry extension not found");
            }

            Asn1OctetString ext = entry.GetExtensionValue(X509Extensions.ReasonCode);

            if (ext != null)
            {
                DerEnumerated reasonCode = (DerEnumerated)X509ExtensionUtilities.FromExtensionValue(ext);

                if (reasonCode.Value.IntValue != CrlReason.PrivilegeWithdrawn)
                {
                    Fail("CRL entry reasonCode wrong");
                }
            }
            else
            {
                Fail("CRL entry reasonCode not found");
            }
        }
        /// <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, byte[] issuingCertificate, string issuingCertificatePassword, out string password)
        {

            AsymmetricKeyParameter caPrivateKey;
            var caCert = ReadCertificateFromBytes(issuingCertificate, issuingCertificatePassword, out caPrivateKey);

            var caAuth = new AuthorityKeyIdentifierStructure(caCert);
            var authKeyId = new AuthorityKeyIdentifier(caAuth.GetKeyIdentifier());

            // ---------------------------

            // Generating Random Numbers
            var randomGenerator = new CryptoApiRandomGenerator();
            var random = new SecureRandom(randomGenerator);

            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-()#$%^&@+=!";
            var rnd = new Random();
            var result = new string(
                Enumerable.Repeat(chars, 15)
                          .Select(s => s[rnd.Next(s.Length)])
                          .ToArray());
            password = result;

            var gen = new X509V3CertificateGenerator();
            var certName = new X509Name("CN=" + subjectName);
            var serialNo = BigInteger.ProbablePrime(120, random);
            gen.SetSerialNumber(serialNo);
            gen.SetSubjectDN(certName);
            gen.SetIssuerDN(caCert.IssuerDN);

            // gen.SetIssuerUniqueID(caCert.IssuerUniqueID.GetBytes())

            gen.SetNotAfter(DateTime.Now.AddYears(100));
            gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
            gen.SetSignatureAlgorithm("SHA256WithRSA"); //("MD5WithRSA");

            var kpgen = new RsaKeyPairGenerator();
            kpgen.Init(new KeyGenerationParameters(random, 2048)); // new SecureRandom(new CryptoApiRandomGenerator()), 2048));
            var subjectKeyPair = kpgen.GenerateKeyPair();
            gen.SetPublicKey(subjectKeyPair.Public);

            //gen.AddExtension(
            //   X509Extensions.AuthorityKeyIdentifier,
            //   false,
            //   authKeyId);

            //gen.AddExtension(
            //    X509Extensions.SubjectKeyIdentifier,
            //    false,
            //    new SubjectKeyIdentifierStructure(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 KeyPurposeID[] { KeyPurposeID.IdKPClientAuth, KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPCodeSigning }));

            //1.3.6.1.5.5.7.3.1 = server authentication
            //1.3.6.1.5.5.7.3.2 = client authentication
            //1.3.6.1.5.5.7.3.3 = code signing

            var certificate = gen.Generate(caPrivateKey);

            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

            // merge into X509Certificate2
            var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());
            var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKey.GetDerEncoded());
            if (seq.Count != 9)
            {
                throw new PemException("malformed sequence in RSA private key");
            }

            var rsa = new RsaPrivateKeyStructure(seq);
            RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
                rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

            //-------------

            //RsaPrivateCrtKeyParameters rsaparams = (RsaPrivateCrtKeyParameters)subjectKeyPair.Private;
            RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rsaparams);
            CspParameters cspParameters = new CspParameters();
            cspParameters.KeyContainerName = Guid.NewGuid().ToString(); // "MyKeyContainer";
            RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(2048, cspParameters);
            rsaKey.ImportParameters(rsaParameters);

            // ------------

            x509.PrivateKey = rsaKey; // DotNetUtilities.ToRSA(rsaparams);


            //var certBytes = DotNetUtilities.ToX509Certificate(certificate).Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx, password);

            //var x5092 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certBytes, password);
            //var rsaPriv = DotNetUtilities.ToRSA(subjectKeyPair.Private as RsaPrivateCrtKeyParameters);
            //x509.PrivateKey = rsaPriv;

            var x509Bytes = x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert);
            System.IO.File.WriteAllBytes(@"C:\mycertx509x.cer", x509Bytes);

            var x509Bytes2 = x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, password);

            System.IO.File.WriteAllBytes(@"C:\mycertx509x.pfx", x509Bytes2);
            System.IO.File.WriteAllText(@"C:\mycertx509x_pass.txt", password);

            //Utility.AddCertToStore(x509, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine);

            return x509Bytes2;
        }
        public static void GenerateCertificate(string subjectName, long serialNumber, DateTime expireOn, bool isCertificateAuthority, System.Security.Cryptography.X509Certificates.X509Certificate2 issuingCertificate, out string thumbprint, out string pemPrivateKey, out string pemPublicCert, out byte[] publicCert, out byte[] pkcs12Data, out string password)
        {

            AsymmetricKeyParameter caPrivateKey;
            var caCert = ReadCertificateFromX509Certificate2(issuingCertificate, out caPrivateKey);

            var caAuth = new AuthorityKeyIdentifierStructure(caCert);
            var authKeyId = new AuthorityKeyIdentifier(caAuth.GetKeyIdentifier());

            // Generating Random Numbers
            var randomGenerator = new CryptoApiRandomGenerator();
            var random = new SecureRandom(randomGenerator);

            var kpgen = new RsaKeyPairGenerator();
            kpgen.Init(new KeyGenerationParameters(random, 2048)); //new SecureRandom(new CryptoApiRandomGenerator()), 2048));
            var subjectKeyPair = kpgen.GenerateKeyPair();

            var gen = new X509V3CertificateGenerator();

            var certName = new X509Name("CN=" + subjectName);

            BigInteger serialNo;
            if (serialNumber == 0)
            {
                serialNo = BigInteger.ProbablePrime(120, random);
            }
            else
            {
                serialNo = BigInteger.ValueOf(serialNumber);
            }

            gen.SetSerialNumber(serialNo);
            gen.SetSubjectDN(certName);
            //gen.SetIssuerDN(certName);
            gen.SetIssuerDN(caCert.IssuerDN);

            var issuerPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(caCert.GetPublicKey());
            var issuerGeneralNames = new GeneralNames(new GeneralName(caCert.IssuerDN));
            var issuerSerialNumber = caCert.SerialNumber;
            var authorityKeyIdentifier = new AuthorityKeyIdentifier(issuerPublicKeyInfo, issuerGeneralNames, issuerSerialNumber);
            gen.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, true, authorityKeyIdentifier);


            gen.SetNotAfter(expireOn);
            gen.SetNotBefore(DateTime.Now.Date);
            gen.SetSignatureAlgorithm("SHA256WithRSA"); //("MD5WithRSA");
            gen.SetPublicKey(subjectKeyPair.Public);

            gen.AddExtension(
                X509Extensions.BasicConstraints.Id,
                true,
                new BasicConstraints(isCertificateAuthority));

            var certificate = gen.Generate(caPrivateKey, random);
            
            //var certificate = gen.Generate(subjectKeyPair.Private, random);

            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
            var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());
            var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKey.GetDerEncoded());
            if (seq.Count != 9)
            {
                throw new PemException("Malformed sequence in RSA private key.");
            }

            var rsa = new RsaPrivateKeyStructure(seq);
            RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
                rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

            RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rsaparams);
            CspParameters cspParameters = new CspParameters();
            cspParameters.KeyContainerName = Guid.NewGuid().ToString(); // "MyKeyContainer";
            RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(2048, cspParameters);
            rsaKey.ImportParameters(rsaParameters);

            x509.PrivateKey = rsaKey; // DotNetUtilities.ToRSA(rsaparams);

            // Generating Random Numbers
            var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-()#$%^&@+=!";
            var rnd = new Random();

            password = new string(
                Enumerable.Repeat(chars, 32)
                          .Select(s => s[rnd.Next(s.Length)])
                          .ToArray());
            thumbprint = x509.Thumbprint.ToLower();
            publicCert = x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert);

            var privateKeyPem = new StringBuilder();
            var privateKeyPemWriter = new PemWriter(new StringWriter(privateKeyPem));
            privateKeyPemWriter.WriteObject(certificate);
            privateKeyPemWriter.WriteObject(subjectKeyPair.Private);
            privateKeyPemWriter.Writer.Flush();
            pemPrivateKey = privateKeyPem.ToString();

            var publicKeyPem = new StringBuilder();
            var utf8WithoutBom = new System.Text.UTF8Encoding(false);
            var publicKeyPemWriter = new PemWriter(new StringWriterWithEncoding(publicKeyPem, utf8WithoutBom));
            publicKeyPemWriter.WriteObject(certificate);
            publicKeyPemWriter.Writer.Flush();
            pemPublicCert = publicKeyPem.ToString();
            pemPublicCert = pemPublicCert.Replace(Environment.NewLine, "\n"); //only use newline and not returns

            pkcs12Data = x509.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx, password);
        }
Exemple #6
0
 public AuthorityKeyIdentifierStructure(AsymmetricKeyParameter pubKey) : base(AuthorityKeyIdentifierStructure.FromKey(pubKey))
 {
 }
Exemple #7
0
 public AuthorityKeyIdentifierStructure(X509Certificate certificate) : base(AuthorityKeyIdentifierStructure.FromCertificate(certificate))
 {
 }
        public X509Certificate2 Build()
        {
            // Generating Random Numbers
            var randomGenerator = new CryptoApiRandomGenerator();
            var random = new SecureRandom(randomGenerator);

            // The Certificate Generator
            var certificateGenerator = new X509V3CertificateGenerator();

            // Serial Number
            var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
            certificateGenerator.SetSerialNumber(serialNumber);

            // Signature Algorithm
            certificateGenerator.SetSignatureAlgorithm("SHA256WithRSA");

            // Issuer and Subject Name
            certificateGenerator.SetIssuerDN(new X509Name(_issuerName ?? _subjectName));
            certificateGenerator.SetSubjectDN(new X509Name(_subjectName));

            // Authority Key Identifier
            if (_issuer != null)
            {
                var authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(
                    DotNetUtilities.FromX509Certificate(_issuer));
                certificateGenerator.AddExtension(
                    X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifier);
            }

            // Basic Constraints - certificate is allowed to be used as intermediate.
            certificateGenerator.AddExtension(
                X509Extensions.BasicConstraints.Id, true, new BasicConstraints(_intermediate));

            // Valid For
            certificateGenerator.SetNotBefore(_notBefore ?? DateTime.UtcNow.Date);
            certificateGenerator.SetNotAfter(_notAfter ?? DateTime.UtcNow.Date.AddYears(2));

            // Subject Public Key
            var keyGenerationParameters = new KeyGenerationParameters(random, _keyStrength);
            var keyPairGenerator = new RsaKeyPairGenerator();
            keyPairGenerator.Init(keyGenerationParameters);

            var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
            var issuerKeyPair = _issuerPrivateKey == null
                ? subjectKeyPair
                : DotNetUtilities.GetKeyPair(_issuerPrivateKey);

            certificateGenerator.SetPublicKey(subjectKeyPair.Public);

            // selfsign certificate
            var certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);

            // merge into X509Certificate2
            return new X509Certificate2(certificate.GetEncoded())
            {
                PrivateKey = ConvertToRsaPrivateKey(subjectKeyPair)
            };
        }