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
  • Comments 98

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)

  • Thank you very much Alex...........

  • Hi All,

    When i'm submitting my request to CA my request is going into pending folder .

    iDisposition = objCertRequest.Submit(

                       CR_IN_BASE64 | CR_IN_FORMATANY,

                       strRequest,

                       null,

                       strCAConfig

                   );

    I'm getting iDisposition =5 which is pending .

    Am i doing any thin wrong how to issue the certificate directly i mean not to pending stage.

    Thanks

    Rizwan

  • Hi Rizwan,

    That should be something to configure on the server. CAs can issue certs directly or wait for an admin's approval.

    Regards,

    Alex

  • Thanks Alex for your quick help,

    Once it is pending and approved by Admin then how to fetch the same request which is now signed by CA server?

    I must be very much thank full to you for your blog this has helped me a lot.

    Thanks

    Rizwan

  • We have resolved this issue you were right we need to make some changes into the config on CA and it started working.

    Thanks

    Rizwan

  • Hi Alex,

    Now i've generated CSR and got it signed back from CA server.

    When I'm trying to convert into Xenroll.CreatePFXfile("Password",certPath) i get error that this is not possible with current key.

    I'm able to successfully import that certificate into certificate store.When i go to certificate store and try to export certificate private key manually so i find that option grayed out.

    Any idea for this issue.

    Because i wanted to extract my private key from signed certificate and make it password protected and send to mail.

    Thanks

    Rizwan

  • Hi Rizwan,

    You need to mark your key as exportable when creating the request. There are flags for that as you can see here:

    blogs.msdn.com/.../certenroll-cx509enrollment-p-createrequest-returns-error-0x8009000b.aspx

    Regards,

    Alex

  • Thanks Alex for all your help, it worked and i'm able to generate certificate and convert to .pfx file.

    Any Idea how to revoke the certificate which CA has issued?

    I was looking and  found the command through certutill.exe ,but same i wanted to do through my c# code.

    Please guide.

    Thanks in advance for all your help so far.

    Rizwan

  • Hi Rizwan, I don't have any sample to revoke certs, but I guess you can use this method:

    ICertAdmin2::RevokeCertificate method

    msdn.microsoft.com/.../aa383251(VS.85).aspx

    Here you have a sample that shows how to use certadmin in .NET, in case it helps as a base:

    blogs.msdn.com/.../how-to-export-issued-certificates-from-a-ca-programatically-c.aspx

  • Thanks Alex for all your help and quick response for my queries...

    I'm creating .PFX file using xenroll.createpfxfile which accepts password and file path.

    I've a requirement to createpfx file without password.

    Any idea how to do that using xenroll.dll

    Thanks

    Rizwan

  • Hi Rizwan,

    I don't remember much about xenroll, as it has been deprecated for years, but I would have assumed that passing "" or null as the password would do...

  • If i pass it null or "" then also it ask for password and without entering password able to proceed further, but i just wanted to get rid of password box, so it should't even show me the  password option ...

    Thanks

    Rizwan

  • Hi Alex

    If i pass it null or "" then also it ask for password and without entering password able to proceed further, but i just wanted to get rid of password box, so it should't even show me the  password option ...

    Or do we have any other COM component available who does this?

    Thanks

    Rizwan

  • Thank you very much for your blog and your quick response ,this blog actually helped me a lot.

    You are really great.

    Thanks

    Rizwan

  • certEnroll.createPKCS10(dn, ClientAuthentication)

    method is working fine when called using console app but on IIS server its not working the moment its coming here and throwing exception

    Exception : The system cannot find the file specified. (Exception from HRESULT: 0x80070002)

    Any help please

    Thanks

    Rizwan

Page 5 of 7 (98 items) «34567
Leave a Comment
  • Please add 6 and 7 and type the answer here:
  • Post
Translate This Page