title: When requesting a certificate, how do I get a pfx blob?
body: <p>The following <a href="http://blogs.msdn.com/b/alejacma/archive/2008/09/05/how-to-create-a-certificate-request-with-certenroll-and-net-c.aspx?PageIndex=2" rel="nofollow">code</a> is used to request a certificate from an ADCS instance.</p>
  
  <p>How do I extract the request, and the finalized pfx blob (and password protect it) for external storage?</p>
  
  <pre><code>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);
              }
          }      
      }
  }
  </code></pre>
  
  <p>The problem with the code is that I don't want to store crypto material in the Windows DPAPI, and in particular I don't want to "install" the certificate, since the crypto material needs to be securely sent and shared among multiple computers.</p>
  
  <p>The particular lines of code I'm having trouble with include this: </p>
  
  <pre><code>        // Install the certificate
              objEnroll.Initialize(X509CertificateEnrollmentContext.ContextUser);
              objEnroll.InstallResponse(
                  InstallResponseRestrictionFlags.AllowUntrustedRoot,
                  strCert,
                  EncodingType.XCN_CRYPT_STRING_BASE64,
                  null
              );
  </code></pre>
  
  <p>I also want to save and import the certificate request from a custom store... again not DPAPI</p>