我的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?
答案 0 :(得分: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函数获取cert句柄时(确保它不等于IntPtr.zero
。
2)然后使用Marshal.PtrToStructure
方法将指针复制到结构:
CapiNative.CERT_CONTEXT certcontext = (CapiNative.CERT_CONTEXT)Marshal.PtrToStructure(certHandle, typeof(CapiNative.CERT_CONTEXT));
3)然后你可以将pCertInfo
结构的CERT_CONTEXT
成员转换为CERT_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类型。您无法将托管类/结构传递给非托管代码/内存。
答案 1 :(得分:0)
为什么不在.NET中使用X509Store类有什么特别的原因?