Is there a method in .Net to import a PFX file along with the certificate chain to a certificate store?

Though not directly related to distributed services but I see this information useful, especially for developers doing certificate related operations in their code (which might be a WCF application).

The answer is NO. There’s no way to open a full cert chain in the .Net framework without a P/Invoke to the PFXImportCertStore() API. X509Certificate2 will only open the leaf certificate form the PFX.

The code to do a P/Invoke to PFXImportCertStore() for importing a certificate along with its chain to a user’s personal certificate store (“MY” store) is as shown below:

using System;

using System.IO;

using System.Runtime.InteropServices;

 public class Crypto

{

    #region CONSTS

 

    // #define CERT_STORE_ADD_REPLACE_EXISTING 3

    public const Int32 CERT_STORE_ADD_REPLACE_EXISTING = 3;

 

    // #define CERT_STORE_PROV_SYSTEM ((LPCSTR) 10)

    public const Int32 CERT_STORE_PROV_SYSTEM = 10;

 

    // #define CERT_SYSTEM_STORE_CURRENT_USER_ID 1

    public const Int32 CERT_SYSTEM_STORE_CURRENT_USER_ID = 1;

 

    // #define CERT_SYSTEM_STORE_LOCATION_SHIFT 16

    public const Int32 CERT_SYSTEM_STORE_LOCATION_SHIFT = 16;

 

    // #define CERT_SYSTEM_STORE_CURRENT_USER \

    // (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT)

    public const Int32 CERT_SYSTEM_STORE_CURRENT_USER =

        CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT;

 

    #endregion

 

    #region STRUCTS

 

    // typedef struct _CRYPTOAPI_BLOB

    // {

    // DWORD cbData;

    // BYTE *pbData;

    // } CRYPT_HASH_BLOB, CRYPT_INTEGER_BLOB,

    // CRYPT_OBJID_BLOB, CERT_NAME_BLOB;

    [StructLayout(LayoutKind.Sequential)]

    public struct CRYPT_DATA_BLOB

    {

        public int cbData;

        public IntPtr pbData;

    }

 

    // typedef struct _CERT_CONTEXT {

    // DWORD dwCertEncodingType;

    // BYTE *pbCertEncoded;

    // DWORD cbCertEncoded;

    // PCERT_INFO pCertInfo;

    // HCERTSTORE hCertStore;

    //} *PCERT_CONTEXT;

    [StructLayout(LayoutKind.Sequential)]

    public struct CERT_CONTEXT

    {

        public uint dwCertEncodingType;

        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]

        public byte[] pbCertEncoded;

        public uint cbCertEncoded;

        public IntPtr pCertInfo;

        public IntPtr hCertStore;

    }

 

    #endregion

 

    #region FUNCTIONS (IMPORTS)

 

    [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]

    public static extern IntPtr CertOpenStore(

        int storeProvider,

        uint dwMsgAndCertEncodingType,

        IntPtr hCryptProv,

        uint dwFlags,

        String cchNameString);

 

    [DllImport("Crypt32.dll", SetLastError = true)]

    public static extern IntPtr PFXImportCertStore(

     ref CRYPT_DATA_BLOB pPfx,

     [MarshalAs(UnmanagedType.LPWStr)] String szPassword,

     uint dwFlags);

 

    [DllImport("Crypt32.dll", SetLastError = true)]

    public static extern Boolean CertAddCertificateContextToStore(

        IntPtr hCertStore,

        IntPtr pCertContext,

        Int32 dwAddDisposition,

        ref IntPtr ppStoreContext

    );

 

    [DllImport("Crypt32.DLL", SetLastError = true)]

    public static extern IntPtr CertEnumCertificatesInStore(

        IntPtr storeProvider,

        IntPtr prevCertContext

    );

 

    [DllImport("Crypt32.dll", SetLastError = true)]

    public static extern Boolean CertCloseStore(

        IntPtr hCertStore,

        Int32 dwFlags

    );

 

    #endregion

}

 

namespace ImportCert

{

    class Program

    {

        //Reads a file.

        internal static byte[] ReadFile(string fileName)

        {

            FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);

            int size = (int)f.Length;

            byte[] data = new byte[size];

            size = f.Read(data, 0, size);

            f.Close();

            return data;

        }

 

        static void Main(string[] args)

        {

            //Test for correct number of arguments.

            if (args.Length < 2)

            {

                Console.WriteLine("Usage: ImportCert <PFX filename> password");

                return;

            }

 

            try

            {

                IntPtr hCryptProv = IntPtr.Zero;

                IntPtr hCertStore = Crypto.CertOpenStore(Crypto.CERT_STORE_PROV_SYSTEM,

                                                          0,

                                                          hCryptProv,

                                                          Crypto.CERT_SYSTEM_STORE_CURRENT_USER,

                                                          "MY");

 

                if (hCertStore != IntPtr.Zero)

                {

                    byte[] rawData = ReadFile(args[0]);

 

                    Crypto.CRYPT_DATA_BLOB ppfx = new Crypto.CRYPT_DATA_BLOB();

                    ppfx.cbData = rawData.Length;

                    ppfx.pbData = Marshal.AllocHGlobal(rawData.Length);

                    Marshal.Copy(rawData, 0, ppfx.pbData, rawData.Length);

 

                    IntPtr hMemStore = Crypto.PFXImportCertStore(ref ppfx, args[1], 0);

 

                    if (hMemStore != IntPtr.Zero)

                    {

                        IntPtr pctx = IntPtr.Zero;

                        IntPtr pStoreContext = IntPtr.Zero;

 

                        while (IntPtr.Zero != (pctx = Crypto.CertEnumCertificatesInStore(hMemStore, pctx)))

                        {

                            Crypto.CertAddCertificateContextToStore(hCertStore,

                                                                     pctx,

                                                                     Crypto.CERT_STORE_ADD_REPLACE_EXISTING,

                                                                     ref pStoreContext);

                        }

 

                        Crypto.CertCloseStore(hMemStore, 0);

                    }

                    Crypto.CertCloseStore(hCertStore, 0);

                }

            }

            catch (Exception e)

            {

                Console.WriteLine(e.Message);

            }

        }

    }

}

Reference:

msdn.microsoft.com/en-us/library/aa387314(v=vs.85).aspx

 

Shamik Misra
Escalation Services, Microsoft Developer Support

Comments

  • Anonymous
    February 05, 2012
    Same can be verified through WCF config setting, isnt it?