1

My Silverlight app needs to access X509Store through native methods like this :

public class CapiNative
    {
        public const string MY = "MY";
        public const uint PKCS_7_ASN_ENCODING = 0x00010000;
        public const uint X509_ASN_ENCODING = 0x00000001;
        public const uint CERT_FIND_SUBJECT_STR = 0x00080007;
        public const int ACCESS_DENIED = 5;

        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CertOpenSystemStore(
            IntPtr hCryptProv,
            string storename);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertFindCertificateInStore(
            IntPtr hCertStore,
            uint dwCertEncodingType,
            uint dwFindFlags,
            uint dwFindType,
            [In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString,
            IntPtr pPrevCertCntxt);

        internal static void CertEnumCertificatesInStore(IntPtr storeHandle, IntPtr certHandle)
        {
            throw new NotImplementedException();
        }
    }

    public IntPtr FindCert(ref string err)
    {
        IntPtr storeHandle = CapiNative.CertOpenSystemStore(
            IntPtr.Zero,
            CapiNative.MY);

        if (Marshal.GetLastWin32Error() == CapiNative.ACCESS_DENIED)
        {
            err = "Access Denied to the X509Store";
            return IntPtr.Zero;
        }


        try
        {
            IntPtr certHandle = CapiNative.CertFindCertificateInStore(
           storeHandle,
           CapiNative.PKCS_7_ASN_ENCODING | CapiNative.X509_ASN_ENCODING,
           0,
           CapiNative.CERT_FIND_SUBJECT_STR,
           _subject,
           IntPtr.Zero);

           X509Certificate foundcert = new X509Certificate(certHandle);
           Console.WriteLine("\nFound certificate with SubjectName string \"{0}\"",_subject); 
           Console.WriteLine("SubjectName:\t{0}", foundcert.Issuer);
           Console.WriteLine("Serial No:\t{0}", foundcert.GetSerialNumberString());
           Console.WriteLine("HashString:\t{0}" , foundcert.GetCertHashString());


            return certHandle;
        }
        catch (Exception e)
        {
            err = "Error getting certificate " + e.Message;
            return IntPtr.Zero;
        }
    }

When I'm using the constructor X509Certificate(IntPtr) I get a MethodAccessException, I guess I can't use this method in Silverlight.

I also tried to use this technique :

https://stackoverflow.com/a/17340419/969881

Like this :

 public X509Certificate IntPtrToObject(IntPtr ptrToUnwrap, ref string err)
 {
      if (ptrToUnwrap == IntPtr.Zero)
      {
          return null;
      }

      try
      {
           X509Certificate x509Cert = new X509Certificate();
           System.Runtime.InteropServices.Marshal.PtrToStructure(ptrToUnwrap, x509Cert);
           return x509;
      }
      catch (Exception e)
      {
           err = e.Message;
           return null;
      }

 }

But I get the following error message :

Object contains non-primitive or non-blittable data. The structure must be specified blittable or have information provided. Parameter name: structure

Is it possible to parse a X509Certificate with the P/Invoke methods ?

Community
  • 1
  • 1
Thordax
  • 1,673
  • 4
  • 28
  • 54

2 Answers2

1

Unfortunately, I'm not a Silverlight expert, and don't know what functionality is stripped there, however you can use workaround:

1) define CERT_CONTEXT structure as follows

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct CERT_CONTEXT {
    public Int32 dwCertEncodingType;
    public IntPtr pbCertEncoded;
    public Int32 cbCertEncoded;
    public IntPtr pCertInfo;
    public IntPtr hCertStore;
}

and when acquire cert handle from CertFindCertificateInStore function (ensure if this is not equals to IntPtr.zero.

2) Then use Marshal.PtrToStructure method to copy pointer to a structure:

CapiNative.CERT_CONTEXT certcontext = (CapiNative.CERT_CONTEXT)Marshal.PtrToStructure(certHandle, typeof(CapiNative.CERT_CONTEXT));

3) then you can transfortm pCertInfo member of CERT_CONTEXT structure to CERT_INFO structure, but I would try to grab raw bytes from this structure:

byte[] rawData = new byte[certContext.cbCertEncoded];
Marshal.Copy(certContext.pbCertEncoded, rawData, 0, rawData.Length);
X509Certificate2 cert = new X509Certificate2(rawData);

BTW, do not forget to close certificate store after completing the certificate access to avoid memory leaks. Store is closed by using a CertCloseStore function.

BTW2, the code part from your original posting:

X509Certificate x509Cert = new X509Certificate();
System.Runtime.InteropServices.Marshal.PtrToStructure(ptrToUnwrap, x509Cert);
return x509;

is incorrect, because PtrToStructure expects a C-style structure with layout information, and its members must be of blittable types. You can't pass managed classes/structures to unmanaged code/memory.

Crypt32
  • 12,850
  • 2
  • 41
  • 70
0

Is there any specific reason why not to use X509Store class in .NET?

Crypt32
  • 12,850
  • 2
  • 41
  • 70