2014-10-06 29 views
0

我的Silverlight應用程序需要通過本地方法是這樣來訪問的X509Store:使用x509證書構造函數的IntPtr產生MethodAccessException

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; 
     } 
    } 

當我使用構造X509證書(IntPtr的),我得到一個MethodAccessException,我想我可以在Silverlight中不使用此方法。

我也嘗試過使用這種技術:

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

像這樣:

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; 
     } 

} 

,但我得到了以下錯誤消息:

對象包含非基本或不可接受的數據。結構 必須指定爲blittable或提供信息。參數 名稱:結構

是否可以使用P/Invoke方法解析X509Certificate?

回答

0

爲什麼不在.NET中使用X509Store類有什麼具體原因?

+0

是的,我不能在Silverlight中這樣做,它沒有實現。 – Thordax 2014-10-22 09:07:30

+0

看到我的另一個職位解決方法。 – Crypt32 2014-10-22 11:10:37

1

不幸的是,我不是一個Silverlight的專家,不知道有什麼功能被剝離在那裏,但是你可以使用的解決方法:

1)定義CERT_CONTEXT結構如下

[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; 
} 

和當從CertFindCertificateInStore功能獲取證書手柄(確保如果不等於IntPtr.zero

2)。然後使用Marshal.PtrToStructure方法指針複製到一個結構:

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

3),那麼你可以transfortm成員結構的CERT_CONTEXTpCertInfoCERT_INFO結構,但我會嘗試從這種結構搶原始字節:

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

BTW,不要忘記關閉證書存儲器後,完成證書訪問以避免內存泄漏。商店通過使用CertCloseStore函數關閉。

BTW2,代碼部分從原始發帖:

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

是不正確的,因爲PtrToStructure期待與佈局信息的C風格的結構,其成員必須是Blittable型的。您不能將託管類/結構傳遞給非託管代碼/內存。