request certificate from CA with template through code

Viewed 366

I want to create new certificate for each one of our users ( signing digitaly accounting documents ) using our CA template pragmatically. manually I've managed to do so VIA

https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/create-code-signing-cert-for-windows-defender-application-control#feedback

I've also manage to create a simple Request, using very wrong methodologies via

string certificatePath = Server.MapPath("~/Files/comp-crt-ca.crt");
        string privateKeyPath = Server.MapPath("~/Files/comp-pem-ca.key");
        string certificateText = System.IO.File.ReadAllText(certificatePath);
        string privateKeyText = System.IO.File.ReadAllText(privateKeyPath);
        System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificatePath);
pass = "111111";  
            X509Certificate certBaseForm = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(certificate);
            var newStore = new Pkcs12Store();
            var certEntry = new X509CertificateEntry(certBaseForm);

            newStore.SetCertificateEntry(signatureAliasTemplate, certEntry);
            newStore.SetKeyEntry(signatureAliasTemplate, new AsymmetricKeyEntry(kp.Private), new[] { certEntry });

            using (var certFile = System.IO.File.Create(pathPfx))
            {
                newStore.Save(certFile, pass.ToCharArray(), new SecureRandom(new CryptoApiRandomGenerator()));
            }

            System.Security.Cryptography.X509Certificates.X509Certificate2 newCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(pathPfx);
            using (System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(
                System.Security.Cryptography.X509Certificates.StoreName.CertificateAuthority,
                System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine))
            {
                store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite);
                store.Add(newCert); //where cert is an X509Certificate object
            }

obviously it's a very bad practice due to the fact the .pem is on my root, but i did it just to see if the cert would be created - and it does, but on the root authority, not the template.

I've added a screenshot to demonstrate , the last row was created by my code , the one with the "signserver-newdoc_4". the rest - created manually and they are what i try to achieve enter image description here

can anyone point me to the direction ? i've been through tons of articles in the past 2 weeks .. nothing that did what i want which seems to me, suppose to be simple if you know the right libraries.

1 Answers

This code will request a certificate for the given templateName (template stored in your AD) and store it in the local current user certificate store.

It can be used in .NET Core projects but will only work on Windows because of the used API (via COM).

Look at this sample code for more details / if you need to set a custom subject name.

void Enroll(string templateName, string friendlyName)
{
    var typ = Type.GetTypeFromCLSID(new Guid("{884E2046-217D-11DA-B2A4-000E7BBB2B09}"), true); // CX509Enrollment
    dynamic cX509Enrollment = Activator.CreateInstance(typ);
    try
    {
        cX509Enrollment.InitializeFromTemplateName(
            1, // X509CertificateEnrollmentContext.ContextUser
            templateName);

        cX509Enrollment.CertificateFriendlyName = friendlyName;
        cX509Enrollment.Enroll();
    }
    finally
    {
        Marshal.ReleaseComObject(cX509Enrollment);
    }
}
Related