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?