【问题标题】:Using X509Certificate constructor with IntPtr generates MethodAccessException将 X509Certificate 构造函数与 IntPtr 一起使用会生成 MethodAccessException
【发布时间】:2014-10-06 20:36:39
【问题描述】:

我的 Silverlight 应用需要通过这样的原生方法访问 X509Store:

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

当我使用构造函数 X509Certificate(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 数据。结构 必须指定 blittable 或提供信息。范围 名称:结构

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

【问题讨论】:

    标签: c# silverlight x509certificate


    【解决方案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) 那么你可以将CERT_CONTEXT 结构的pCertInfo 成员转换为CERT_INFO 结构,但我会尝试从这个结构中获取原始字节:

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

    顺便说一句,完成证书访问后不要忘记关闭证书存储以避免内存泄漏。使用 CertCloseStore 函数关闭商店。

    顺便说一句,您原始帖子中的代码部分:

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

    不正确,因为PtrToStructure 期望具有布局信息的 C 样式结构,并且其成员必须是可位点类型。您不能将托管类/结构传递给非托管代码/内存。

    【讨论】:

      【解决方案2】:

      在 .NET 中为什么不使用 X509Store 类有什么具体原因吗?

      【讨论】:

      • 是的,我不能在 Silverlight 中这样做,它没有实现。
      猜你喜欢
      • 2012-04-14
      • 1970-01-01
      • 1970-01-01
      • 2011-12-01
      • 1970-01-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多