NullifyNetwork

The blog and home page of Simon Soanes
Skip to content
[ Log On ]

I needed to get the unmanaged container name of an X509Certificate2 in order to be able to get access to the equivalent private key for it on Windows Mobile (I also wanted to be able to use the same routine on Windows CE and Win32 so this works as-is on all platforms).

No decent commentary but hopefully it will help someone else who is stuck without the container name or something.


#region Structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPT_KEY_PROV_INFO
{
      [MarshalAs(UnmanagedType.LPWStr)]
      public string pwszContainerName;
      [MarshalAs(UnmanagedType.LPWStr)]
      public string pwszProvName;
      public uint dwProvType;
      public uint dwFlags;
      public uint cProvParam;
      public IntPtr rgProvParam;
      public uint dwKeySpec;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPTOAPI_BLOB
{
    public uint cbData;
    public IntPtr pbData;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CERT_DSS_PARAMETERS
{
    public CRYPTOAPI_BLOB p;
    public CRYPTOAPI_BLOB q;
    public CRYPTOAPI_BLOB g;
}
#endregion

[DllImport("crypt32.dll")]
public static extern bool CertGetCertificateContextProperty(IntPtr pCertContext, 
	uint dwPropId, IntPtr pvData, ref uint pcbData);

public CRYPT_KEY_PROV_INFO GetCertificateContextProperty(X509Certificate2 certificate)
{
     //call once to get the size, call again to get the data
     try
     {
         IntPtr certhandle = certificate.Handle;
         uint pcbData = 0;
         if (CertGetCertificateContextProperty(certhandle, 2, IntPtr.Zero, ref pcbData))
         {
             IntPtr memoryChunk = Marshal.AllocHGlobal((int)pcbData);
             try
             {
       		    if (CertGetCertificateContextProperty(certhandle, 2, memoryChunk, 
			ref pcbData))
                  {
                    CRYPT_KEY_PROV_INFO context = 
				(CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(memoryChunk, 
				typeof(CRYPT_KEY_PROV_INFO));
                     return context;
                  }
                  else
                  {
                      throw new Exception("Failed to fetch the Certificate Context 
Property, possibly due to the certificate being modified during the call.  Please try again!");
                  }
              }
              finally
              {
                  Marshal.FreeHGlobal(memoryChunk);
              }
          }
      }
      finally
      {
          //dispose of certhandle or not??
      }
      throw new Exception("Failed to fetch the Certificate Context Property");
}

(Incidentally the extra structures are handy for doing other operations with the certificate so I left them there - the blob particularly is used in a lot of places in the CryptoAPI)

Permalink