Decrypt my World

Cryptography, Security, Debugging and more!

How to create a certificate request with CertEnroll and .NET (C#)

How to create a certificate request with CertEnroll and .NET (C#)

Rate This

Hi all,

The following C# sample shows how to use CertEnroll COM component to create a certificate request, send the request to the CA, get the response from the CA, and install the new certificate in the machine:

(Note that this sample is a WinForms app with 3 buttons -createRequestButton, sendRequestButton, acceptPKCS7Button- and 2 textboxes -requestText & responseText-)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

//  Add the CertEnroll namespace
using CERTENROLLLib;
using CERTCLIENTLib;

namespace CATest
{
    public partial class Form1 : Form
    {
        private const int CC_DEFAULTCONFIG = 0;
        private const int CC_UIPICKCONFIG = 0x1;
        private const int CR_IN_BASE64 = 0x1;
        private const int CR_IN_FORMATANY = 0;
        private const int CR_IN_PKCS10 = 0x100;
        private const int CR_DISP_ISSUED = 0x3;
        private const int CR_DISP_UNDER_SUBMISSION = 0x5;
        private const int CR_OUT_BASE64 = 0x1;
        private const int CR_OUT_CHAIN = 0x100;

        public Form1()
        {
            InitializeComponent();
        }

        // Create request
        private void createRequestButton_Click(object sender, EventArgs e)
        {
            //  Create all the objects that will be required
            CX509CertificateRequestPkcs10 objPkcs10 = new CX509CertificateRequestPkcs10Class();
            CX509PrivateKey objPrivateKey = new CX509PrivateKeyClass();
            CCspInformation objCSP = new CCspInformationClass();
            CCspInformations objCSPs = new CCspInformationsClass();
            CX500DistinguishedName objDN = new CX500DistinguishedNameClass();
            CX509Enrollment objEnroll = new CX509EnrollmentClass();
            CObjectIds objObjectIds = new CObjectIdsClass();
            CObjectId objObjectId = new CObjectIdClass();
            CX509ExtensionKeyUsage objExtensionKeyUsage = new CX509ExtensionKeyUsageClass(); 
            CX509ExtensionEnhancedKeyUsage objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsageClass();
            string strRequest;

            try
            {
                requestText.Text = "";

                //  Initialize the csp object using the desired Cryptograhic Service Provider (CSP)
                objCSP.InitializeFromName(
                    "Microsoft Enhanced Cryptographic Provider v1.0"
                );

                //  Add this CSP object to the CSP collection object
                objCSPs.Add(
                    objCSP
                );

                //  Provide key container name, key length and key spec to the private key object
                //objPrivateKey.ContainerName = "AlejaCMa";
                objPrivateKey.Length = 1024;
                objPrivateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE;
                objPrivateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES; 
                objPrivateKey.MachineContext = false;

                //  Provide the CSP collection object (in this case containing only 1 CSP object)
                //  to the private key object
                objPrivateKey.CspInformations = objCSPs;

                //  Create the actual key pair
                objPrivateKey.Create();

                //  Initialize the PKCS#10 certificate request object based on the private key.
                //  Using the context, indicate that this is a user certificate request and don't
                //  provide a template name
                objPkcs10.InitializeFromPrivateKey(
                    X509CertificateEnrollmentContext.ContextUser, 
                    objPrivateKey, 
                    ""
                );

                // Key Usage Extension 
                objExtensionKeyUsage.InitializeEncode(
                    X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE | 
                    X509KeyUsageFlags.XCN_CERT_NON_REPUDIATION_KEY_USAGE | 
                    X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE | 
                    X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
                );
                objPkcs10.X509Extensions.Add((CX509Extension)objExtensionKeyUsage);

                // Enhanced Key Usage Extension
                objObjectId.InitializeFromValue("1.3.6.1.5.5.7.3.2"); // OID for Client Authentication usage
                objObjectIds.Add(objObjectId);
                objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
                objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage);

                //  Encode the name in using the Distinguished Name object
                objDN.Encode(
                    "CN=AlejaCMa",
                    X500NameFlags.XCN_CERT_NAME_STR_NONE
                );

                //  Assing the subject name by using the Distinguished Name object initialized above
                objPkcs10.Subject = objDN;

                // Create enrollment request
                objEnroll.InitializeFromRequest(objPkcs10);
                strRequest = objEnroll.CreateRequest(
                    EncodingType.XCN_CRYPT_STRING_BASE64
                );

                requestText.Text = strRequest;

            } catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        // Submit request to CA and get response 
        private void sendRequestButton_Click(object sender, EventArgs e)
        {
            //  Create all the objects that will be required
            CCertConfig objCertConfig = new CCertConfigClass();
            CCertRequest objCertRequest = new CCertRequestClass();
            string strCAConfig;
            string strRequest;
            int iDisposition;
            string strDisposition;
            string strCert;

            try
            {
                strRequest = requestText.Text;

                // Get CA config from UI
                //strCAConfig = objCertConfig.GetConfig(CC_DEFAULTCONFIG);
                strCAConfig = objCertConfig.GetConfig(CC_UIPICKCONFIG);                

                // Submit the request
                iDisposition = objCertRequest.Submit(
                    CR_IN_BASE64 | CR_IN_FORMATANY,
                    strRequest,
                    null,
                    strCAConfig
                );

                // Check the submission status
                if (CR_DISP_ISSUED != iDisposition) // Not enrolled
                {
                    strDisposition = objCertRequest.GetDispositionMessage();

                    if (CR_DISP_UNDER_SUBMISSION == iDisposition) // Pending
                    {
                        MessageBox.Show("The submission is pending: " + strDisposition);
                        return;
                    }
                    else // Failed
                    {
                        MessageBox.Show("The submission failed: " + strDisposition);
                        MessageBox.Show("Last status: " + objCertRequest.GetLastStatus().ToString());
                        return;
                    }
                }

                // Get the certificate
                strCert = objCertRequest.GetCertificate(
                    CR_OUT_BASE64 | CR_OUT_CHAIN
                );

                responseText.Text = strCert;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        // Install response from CA
        private void acceptPKCS7Button_Click(object sender, EventArgs e)
        {
            //  Create all the objects that will be required
            CX509Enrollment objEnroll = new CX509EnrollmentClass();
            string strCert;
            
            try
            {
                strCert = responseText.Text;

                // Install the certificate
                objEnroll.Initialize(X509CertificateEnrollmentContext.ContextUser);
                objEnroll.InstallResponse(
                    InstallResponseRestrictionFlags.AllowUntrustedRoot,
                    strCert,
                    EncodingType.XCN_CRYPT_STRING_BASE64,
                    null
                );

                MessageBox.Show("Certificate installed!");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }      
    }
}

I hope this helps.

Cheers,

 

Alex (Alejandro Campos Magencio)

  • Figured it out:

    string ress = objEnroll.CreatePFX(password, PFXExportOptions.PFXExportEEOnly,                                                  EncodingType.XCN_CRYPT_STRING_BASE64);

    var fs = new FileStream(exportPath, FileMode.Create);

                   fs.Write(Convert.FromBase64String(ress), 0, Convert.FromBase64String(ress).Length);

                   fs.Close();

  • Is there a way to get pfx blob without installing response to local certificate store?

    Something like:

    1. objEnroll.Initialize

    2. something i am not aware of :-(

    3. objEnroll.CreatePFX which return me a string

  • Don't know a way. Don't think it's possible, because when we make a request, a partial cert with public/private key pair gets created in the profile of the user/machine. Then we send the request to the CA and its response gets combined to that partial cert to create the definite signed cert. That process requires the cert to be in the profile. You may get the PFX and delete the cert afterwards...

  • Thanks for explanation! I will go with a way you suggested.

  • Is it possible to emulate the function "Automatically Enroll Certificates" using CAPICOM or CertEnroll on XP to force auto enrollment ?

    Via MMC-Certificates - right-click on cert store - All Tasks - Automatically Enroll Certificates

    Thanks - Mike

  • Hi!

    Can you suggest some links or some code snippets for enrollment certificate for template "SmartcardLogon"? What should I change in your code to enroll certificate for smartcard?

    Thanks

  • I was wondering if there was ever a response to a question above because I have the same question but I can't find an answer.

    I have 2 questions:

    1. If I have already a public key, how do I add it to the request. (need this answer)

    2. How to specify the CA to which I wil submit the request. (don't need this answer)

    Thanks in advance

  • I create my own web site to request a certificate.  Everything works fine and I'm able to get the certificate from the CA into a string (strCert).

    Now, I need to send it to the user via the browser and install it on the user's PC.  

    I work with C# (VS2008) and .NET 3.5 inside a Web Application.

    Any thoughts?

  • Hello,

    I also have the exact same situation as Rene. I have written the code on windows server 2008 using asp.net C# to request for certificate. As if I call it from the client machine (another machin within LAN using http://ipaddress/ApplicationName) it works fine. But installResponse only installs it on the server machine. How can I send the certificate response to the Client machine so that it can install it within both IE and Firefox? Please help.

    Thank you in advance.

  • Is this solution good for the site that's hosted on Win2003 server?

    What would be the equivalent CertEnroll.dll COM in 2003?

  • Thanks for this sample!

    When I tried to initialize the IX509Enrollment object from template (InitializeFromTemplateName) - it failed when the minimum supported CA of the template was Windows Server 2008. It worked fine with the same template which its minimum supported CA is Windows Server 2003. (My CA is on Windows Server 2008x64, the code was invoked on the same computer).

    It fails in the CreateRequest stage, with the following exception:

    CertEnroll::CX509Enrollment::p_CreateRequest: Key does not exist. 0x8009000d (-2146893811)

    Any idea?

    Thanks,

    D.

  • hi

    I had a problem with the InitializeFromTemplateName method.

    I used it with succes in dev environment, but when I moved my application in stagin environment, it failed with the error :

    "CertEnroll::CX509CertificateRequestPkcs10::InitializeFromTemplateName: The requested certificate template is not supported by this CA. 0×80094800 (-2146875392)"

    So I tried to change the security but it wasn't the error source

    in fact, InitializeFromTemplateName can take the certificate template object identifier as parameter

    So I used it and it worked

    I described that here :

    http://www.sambeauvois.be/blog/2010/04/the-ix509certificaterequestpkcs10-initializefromtemplatename-adventure/

  • The InitializeFromTemplateName method does work. Make sure you are using the template name opposed to it's display name, if you have spaces in the name, you are using the display name!! :)

  • Hi,

    I'm programing an application that request a certificate from Microsoft Enterprise CA on behalf users. Actually, I can request a certificate (with Certenroll) by using a template. the application is hosted on IIS on the enterprise CA server. But the certificate I request belong to the computer account. My problem is that I don't know request a certificate for a specific user on AD. I have no idea how to map my certificate request to a user! Do you (or anyone) know how? with attribute or methods i should add to your code to do so?

    Thanks,

  • Hi Jawcontact,

    If I understood correctly, you are using server side code to request certificates on behalf of users. If so, the typical solution is to create a PFX file in server side, and send it to user afterwards. So you could implement a solution like the following:

    1. Have server code to request and install the certificate in a  machine certificate store.

    2. The server will export the certificate + private key in PFX format from that cert store, and save it to some database or folder.

    3. User downloads the PFX file to local machine.

    4. Client side code installs the PFX certificate in the user’s certificate store.

    Regards,

    Alex

Page 2 of 7 (100 items) 12345»
Leave a Comment
  • Please add 7 and 4 and type the answer here:
  • Post
Translate This Page