Tuesday, March 14, 2023

Create PFX file from Root files Key/PFX

If you have Root.key and Root.pfx file and you would like to create new PFX file, below is the solution.

I have used. 

  1. .NET Core 6.0 with Visual Studio 2022 Ver 17.4.3
  2. "Portable.BouncyCastle" Version 1.9.0 from Nuget 
  3. "Microsoft.Extensions.Configuration" Version 7.0.0 from Nuget

Here the working solution, use in your class and use it 

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.Pkcs;

using Org.BouncyCastle.Security;

using Org.BouncyCastle.Utilities;

using Org.BouncyCastle.X509;

using System.Security.Cryptography.X509Certificates;

 public void CreateSelfSignedPFXFile()

 {

    string RootKeyFilePath = @"C:\Test\RootFile.key";

    string RootPfxFilePath = @"C:\Test\RootFile.pfx";

    string pass = "Pass123#";

     //Need file name to have all certificate export into this file

     string newPFXFileName = @"C:\Test\NewCertificate.pfx";

     System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(RootPfxFilePath,pass, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet |X509KeyStorageFlags.Exportable);

    string subject = "E=test@test.com, CN=Test Name, OU=ORG, O=LSGS, L=Orlando, ST=MN,C=US";

    try

    {

     using var reader = File.OpenText(RootKeyFilePath);

     AsymmetricKeyParameter? myCAprivateKey = ((AsymmetricCipherKeyPair)new                 Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject())?.Private;

     //Create the cert based on the CA cert privateKey and have new subject

     X509Certificate2 MyCert = GenerateSelfSignedCertificate(subject,                         certificate.Issuer.Replace("S=","ST="), myCAprivateKey, pass);

     //Export as pfx with privatekey

     byte[] certData = MyCert.Export(X509ContentType.Pfx, pass);

    File.WriteAllBytes(newPFXFileName, certData);

    }

    catch (Exception exc){Console.WriteLine(exc.Message);}

     }

     public X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName, AsymmetricKeyParameter? issuerPrivKey, string pass)

     {

     const int keyStrength = 2048;

     // Generating Random Numbers

     CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();

     SecureRandom random = new SecureRandom(randomGenerator);

     // The Certificate Generator

     X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

     // Serial Number

     BigInteger 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

    X509Name subjectDN = new X509Name(subjectName);

    X509Name issuerDN = new X509Name(issuerName);

    certificateGenerator.SetIssuerDN(issuerDN);

    certificateGenerator.SetSubjectDN(subjectDN);

    // Valid For

    DateTime notBefore = DateTime.UtcNow.Date;

    DateTime notAfter = notBefore.AddYears(10);

    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

    AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;

    // selfsign certificate

    Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerPrivKey, random);

    // correcponding private key

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

// merge into X509Certificate2

    X509Certificate2 x509 = new         System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded(),    pass, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet |     X509KeyStorageFlags.Exportable);

     //below does not work for Window

     //Asn1Sequence seq =(Asn1Sequence)Asn1Object.FromStream(info.PrivateKeyData.GetDerEncoded());

     //use this one

     Asn1Sequence seq =(Asn1Sequence)Asn1Object.FromStream(info.PrivateKeyData.GetOctetStream());

     if (seq.Count != 9)

     {

     //throw new PemException("malformed sequence in RSA private key");

     }

     //Create the Private Key

     RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq);

     RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(

     rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

     //below does not work for Window

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

    //use this one 

    var rsa1 = DotNetUtilities.ToRSA(rsaparams);

     var cert = x509.CopyWithPrivateKey(rsa1);

    return cert;

}

Troubleshoots-1

subject should have all correct object , if you pass wrong object then will get error 

Error: "Unknown object id - S - passed to distinguished name"

like: string subject = "E=test@test.com, CN=Test Name, OU=ORG, O=LSGS, L=Orlando, S=MN,C=US";

Ref: for all correct object to be used see here Distinguished Names | Microsoft Learn

Troubleshoots-2

If you are typing wrong password for key certificate, you will get following error 

Error: Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'The specified network password is not correct.'

Make sure you know the correct password.

Troubleshoots-3

If you forgot to create private key at the end then you will get following error 
Error: No Private key
you must need to add private key by using "var cert = x509.CopyWithPrivateKey(rsa1);"

No comments: