如何检查智能卡 reader 中的匹配证书?

How to check for matching Certificate in SmartCard reader?

假设我从 Windows 的密钥库中选择了一个证书,并且在签名时,我需要确保插入 reader 中的智能卡是否正确.. .

下面是一些示例代码:

    // finding the certificate
    X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
    X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true);

    // by thumbprint, there is only one
    certs = certs.Find(X509FindType.FindByThumbprint, "123456BLAHBLAHAE3C", true); 
    X509Certificate2 cert = certs[0];

    RSACryptoServiceProvider key;
    if (cert.HasPrivateKey)
    {
        // software cert
        key = cert.PrivateKey as RSACryptoServiceProvider;
    }
    else
    {
        // certificate from smartcard
        CspParameters csp = new CspParameters(1, "Microsoft Base Smart Card Crypto Provider");
        csp.Flags = CspProviderFlags.UseDefaultKeyContainer;
        key = new RSACryptoServiceProvider(csp);
    }

现在,当我想要签署数据时,我如何知道当前插入的智能卡是否真的是我正在寻找的智能卡(与 Windows' 密钥库中的智能卡相匹配)?

我问这个问题,因为现在当我签署数据时,我收到输入智能卡 PIN 的提示,但我插入的卡甚至不是我选择的凭证。 . 而且它只是签署了数据...

看看这个线程,它或多或少是同一个问题和答案 - find certificate on smartcard currently on reader

经过一整天的故障排除和互联网挖掘。结果我 根本不需要这样做。事实上,这是我自己犯的一个错误。

当您 select 来自商店的证书时,您获得的 X509Certificate 对象实际上拥有它需要的一切,例如 HasPrivateKeyPrivateKey (一个 RSACryptoServiceProvider 对象,不是实际的私钥),并且Windows知道从哪里获得PrivateKey使用这些信息...包括验证智能卡是否在您的reader 是否有正确的智能卡。

我的问题是,在某些时候我使用 cert.GetRawCertData() 获取原始字节来执行我自己的证书验证,最后我从原始字节中重新创建了一个 X509Certificate 对象。 . 我以为它会把原来的 X509Certificate 对象还给我,但是我 大错特错了 HasPrivateKeyPrivateKey 都不见了。

现在,我不确定这是否是 Windows 10 中的新功能。但是正如您在下面看到的,我实际上根本不需要检查卡 reader 中的内容。 ..

为了解决这个问题,我在 reader 中仔细检查智能卡的初衷是确保签名操作确实是使用正确的智能卡完成的(我在 Java 中遇到了问题您可以插入另一张卡并输入错误卡的 PIN,它仍会为您签名)。但是,更好的方法实际上是使用 PublicKey 并验证数据。

// so after you finished signing the data...
// make a new RSACryptoServiceProvider and verify it like this:
RSACryptoServiceProvider rsa = cert.PublicKey.Key as RSACryptoServiceProvider;
Debug.WriteLine("     Verify data >> " + (rsa.VerifyData(data, alg, signature) ? "OK" : "FAILED"));
Debug.WriteLine("Verify signature >> " + (rsa.VerifyHash(hash, alg, signature) ? "OK" : "FAILED"));

注意:不要在 RSACryptoServiceProvider 上使用 using 进行验证,否则将关闭 PublicKey.Key 上的静态句柄,如果尝试验证再次(无论出于何种原因),您将得到一个 Safe Handle has been closed 异常。