获取所有已连接的智能卡列表

3

我正在编写一个类,使用x509证书对XML文档进行签名。我已经能够获取我的智能卡证书并对其进行签名。

然而,为了做到这一点,我必须在Windows密钥库中查找x509证书,因此我必须了解有关我的智能卡的一些信息,例如颁发者名称或序列号。这很好。

但是我想要更方便的方法来获取智能卡证书。我有两个想法:

  • Get all the certificates from the Keystore and look for those who are "coming from a SmartCard". But I dont think i'm able to get such information.
  • Interop with winscard.dll and get some information about the SmartCard connected to my computer, so I could use it to find the right certificate, but this isn't working:

    [DllImport("winscard.dll")]
    public static extern long SCardListCards(
       uint hContext, int pbAtr, 
        int rgguidInterfaces, int cguidInterfaceCount, 
        [MarshalAs(UnmanagedType.LPTStr)] ref string mszCards,
        ref int pcchCards);
    
    [DllImport("winscard.dll")]
    public static extern long SCardEstablishContext(uint dwScope, 
        int pvReserved1, 
        int pvReserved2,
        ref uint phContext); 
    

这里是一个测试方法。变量 string crds 存储了智能卡的列表。

[TestMethod]
public void TestInterop()
{
    uint handle = 0;
    Interop.SCardEstablishContext(0, 0, 0, ref handle);

    string crds = "";
    int pcch = 0;
    Interop.SCardListCards(handle, 0, 0, 0, ref crds, ref pcch);
    Assert.IsTrue(crds != "");
}

每次测试都会失败,因为crds从未更改。
如果我尝试将crds作为byte[]返回:
    [DllImport("winscard.dll", EntryPoint = "SCardListCards")]
    public static extern long SCardListCardsRetBytes(
       uint hContext, int pbAtr,
        int rgguidInterfaces, int cguidInterfaceCount,
        ref byte[] mszCards,
        ref int pcchCards);

将我的byte[] crds赋值后,结果如下:

  • 当我使用byte[] crds = {};初始化时,byte[] {171},为什么会是171?
  • 当我使用byte[] crds = new byte[32];初始化时,byte[] {0},为什么会是0?

我该如何获取智能卡证书来签署XML消息?如果您愿意给我一个额外的答案,为什么我进行的Interop不起作用?


1
SCardListCards没有返回智能卡列表,可能是因为您在错误的域中搜索它们。 尝试在系统上下文中搜索智能卡,而不是用户上下文。 例如:Interop.SCardEstablishContext(2, 0, 0, ref handle); - ClotzA
1
看起来你需要调用SCardListCards两次:第一次是为了获取缓冲区长度,第二次才是真正填充缓冲区。 可以参考这个例子:http://www.pinvoke.net/default.aspx/winscard.scardestablishcontext - ClotzA
是的,那个可以用!但是这个函数并没有做我期望的事情...我的问题还没有解决,不过你帮了很多忙!谢谢。 - Ricardo Pieper
其实我觉得你确实解决了我的问题。现在我可以获取SC的序列号,并将其用作标识符! - Ricardo Pieper
2
@RicardoPieper 你能把可行的代码作为回答发布在你的问题中吗? - g t
显示剩余2条评论
1个回答

0

我发现一种只使用 C# 就可以知道一个 X509Certificate 是否来自智能卡的方法。这解决了我的问题,而且我已经写了一段时间的代码,删除了互操作的 C# 和 C++ 代码。以下是适用于我的方法:

if (certificate.HasPrivateKey)
{
    ICspAsymmetricAlgorithm aa = certificate.PrivateKey as ICspAsymmetricAlgorithm;

    if (aa == null || !aa.CspKeyContainerInfo.HardwareDevice) 
         DoWhateverYouWant(certificate);
}

如果在代码运行时卡片没有连接,对我来说并不是个问题。如果你想获取连接到你的电脑上的智能卡列表,可以使用winscard本地API来实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接