Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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?