Search code examples
.netx509x509certificate2.net-standard-2.0

Generate self-signed X509Certificate2 using .NET Standard 2.0


I am trying to generate new X509Certificate2 in .NET Standard 2.0 library, but I can't find any possible way of doing that. I don't mind using NuGet packages unless they break portability.

Thanks.


Solution

  • I have installed Portable.BouncyCastle 1.8.2 from NuGet, which is compatible with .net Standard >= 1.6.1. With the library this solution works: https://stackoverflow.com/a/22237794/2976142

    Edit

    I've found out, that X509Certificate2.PrivateKey isn't supported in .NET Standard 2.0. So I made my own solution with those libraries. (Just merge of these 2, if you wanted to understand it.):

    The solution

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using Org.BouncyCastle.Asn1;
    using Org.BouncyCastle.Asn1.Pkcs;
    using Org.BouncyCastle.Asn1.X509;
    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.Crypto.Generators;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Crypto.Prng;
    using Org.BouncyCastle.Math;
    using Org.BouncyCastle.OpenSsl;
    using Org.BouncyCastle.Pkcs;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Utilities;
    using Org.BouncyCastle.X509;
    
    namespace Premy.Chatovatko.Client.Cryptography
    {
        public static class X509Certificate2Generator
        {
            
            public static X509Certificate2 GenerateCACertificate(string subjectName = "CN=root ca", int keyStrength = 4096)
            {
                // 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(Int64.MaxValue), random);
                certificateGenerator.SetSerialNumber(serialNumber);
    
                // Signature Algorithm
                const string signatureAlgorithm = "SHA256WithRSA";
                certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
    
                // Issuer and Subject Name
                var subjectDN = new X509Name(subjectName);
                var issuerDN = subjectDN;
                certificateGenerator.SetIssuerDN(issuerDN);
                certificateGenerator.SetSubjectDN(subjectDN);
    
                // Valid For
                var notBefore = DateTime.UtcNow.Date;
                var notAfter = notBefore.AddYears(20);
    
                certificateGenerator.SetNotBefore(notBefore);
                certificateGenerator.SetNotAfter(notAfter);
    
                // Subject Public Key
                AsymmetricCipherKeyPair subjectKeyPair;
                var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
                var keyPairGenerator = new RsaKeyPairGenerator();
                keyPairGenerator.Init(keyGenerationParameters);
                subjectKeyPair = keyPairGenerator.GenerateKeyPair();
    
                certificateGenerator.SetPublicKey(subjectKeyPair.Public);
    
                // Generating the Certificate
                var issuerKeyPair = subjectKeyPair;
    
                // selfsign certificate
                var certificate = certificateGenerator.Generate(issuerKeyPair.Private, random);
    
                // in-memory PFX stream
                var pkcs12Store = new Pkcs12Store();
                var certEntry = new X509CertificateEntry(certificate);
                pkcs12Store.SetCertificateEntry(subjectName, certEntry);
                pkcs12Store.SetKeyEntry(subjectName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certEntry });
                X509Certificate2 keyedCert;
                using (MemoryStream pfxStream = new MemoryStream())
                {
                    pkcs12Store.Save(pfxStream, new char[0], new SecureRandom());
                    pfxStream.Seek(0, SeekOrigin.Begin);
                    keyedCert = new X509Certificate2(pfxStream.ToArray(), string.Empty, X509KeyStorageFlags.Exportable);
                }
    
                return keyedCert;
    
            }
    
        }
    }