Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# X509Certificate2:确定证书私钥是否属于硬件设备,以及它是否需要PIN_C#_Smartcard_X509certificate2 - Fatal编程技术网

C# X509Certificate2:确定证书私钥是否属于硬件设备,以及它是否需要PIN

C# X509Certificate2:确定证书私钥是否属于硬件设备,以及它是否需要PIN,c#,smartcard,x509certificate2,C#,Smartcard,X509certificate2,我正在编写一个程序,使用存储在硬件设备(智能卡)上的证书进行加密 程序必须使用.Net Framework 4.5.2:(不可能更改此选项 我执行的加密操作没有问题:) 序言 据我所知,当包含一个或多个证书的智能卡连接到计算机时,证书将显示在Windows证书存储(CurrentUser/My)中 这由必须安装的智能卡软件管理 由于我的软件必须与任何硬件设备一起工作,最简单的解决方案是弹出一个窗口,让用户选择要使用的证书 第一个问题 我不想显示CurrentUser/My上的所有证书,只想显

我正在编写一个程序,使用存储在硬件设备(智能卡)上的证书进行加密

  • 程序必须使用.Net Framework 4.5.2:(不可能更改此选项
  • 我执行的加密操作没有问题:)
序言

据我所知,当包含一个或多个证书的智能卡连接到计算机时,证书将显示在Windows证书存储(CurrentUser/My)中

这由必须安装的智能卡软件管理

由于我的软件必须与任何硬件设备一起工作,最简单的解决方案是弹出一个窗口,让用户选择要使用的证书

第一个问题

我不想显示CurrentUser/My上的所有证书,只想显示具有连接到计算机的相关硬件的证书

这或多或少就是我正在使用的代码:

X509Store storeObject = new X509Store(StoreName.My, StoreLocation.CurrentUser);

storeObject.Open(OpenFlags.ReadOnly);

foreach (var certificate in storeObject.Certificates)
{
    bool isValid = false;
    if (certificate.HasPrivateKey)
    {
        try
        {
            var rsaKey = certificate.PrivateKey as RSACryptoServiceProvider;
            
            if (rsaKey.CspKeyContainerInfo.HardwareDevice)
            {
                isValid = true;
            }
        }
        catch (Exception ex)
        {
            // just log
        }
    }
}
尽管这个解决方案很难看,但它是我想出的最好的解决方案

在以下情况下,证书属于智能卡:

  • HasPrivateKey是真的
  • 如果智能卡已连接,则向RSACryptServiceProvider强制转换PrivateKey不会引发异常
  • 因此,硬件设备是正确的
问题在于私钥转换:在这个转换过程中,CryptoApi系统似乎执行了很多操作(当然包括对智能卡软件的调用)

这是非常缓慢的,如果智能卡软件出现某种故障,将显示无法控制的错误消息

问题

是否有其他方法确定证书是否属于硬件设备? 以及确定硬件当前是否已连接

第二个问题

证书可能需要PIN码

我必须(这是先决条件)避免Windows输入框要求输入PIN

收集PIN码并在加密操作期间使用它对我来说不是问题

我的问题是了解是否需要PIN码

我在网上找到的任何示例都假设,如果rsaKey.CspKeyContainerInfo.HardwareDevice==true,则需要一个PIN

但我不确定

问题

有没有办法确定证书是否需要PIN码

结论

我也喜欢外部库,只要它们是免费的(最好是开源的)和/或来自微软


多谢各位

在评论中,我提供了Win32互操作解决方案,它可能比延迟操作更快。建议的解决方案将扩展证书属性,从中读取提供商名称(我相信,.NET在内部某处也会这样做?)。然后打开指定的提供程序(CSP或KSP)并从提供程序中查询硬件能力。此解决方案不涉及私钥,也不提示输入PIN

呼叫顺序:

  • 调用函数并查询
    CERT\u KEY\u PROV\u INFO\u PROP\u ID
    属性
  • 函数返回指向结构的指针
  • 结构包含存储提供者名称的
    pwszProvName
    字段
  • 调用函数并将提供程序名称作为参数传递
  • 调用函数并传递在上一步中获得的提供程序句柄和要检索的属性名称。您需要
    NCRYPT\u IMPL\u TYPE\u属性
    属性
  • 接收到的值将存储实现类型的按位标志组合。检查返回值(
    pbOutput
    参数将存储4字节整数值)是否启用了
    NCRYPT\u IMPL\u HARDWARE\u标志
  • 调用完成后释放所有非托管资源。虽然这看起来有点复杂,但根据我的经验,这是确定给定证书的密钥存储位置的最快方法

    重要评论 第4步和第5步可能不适用于所有智能卡提供商(假设您使用传统CSP),但适用于我的。在这种情况下,按如下方式替换步骤4和5:

  • 调用函数以获取提供者的句柄(在步骤3中检索)
  • 调用函数以检索提供程序属性。查询
    PP\u IMPTYPE
    属性
    pbData
    参数将存储一个4字节长的字节数组,该数组表示实现类型的按位组合。检查此值是否启用了
    CRYPT\u IMPL\u HARDWARE1
    标志

  • 我目前正在努力解决与OP类似的问题。在我的情况下,用户必须选择任何证书并设置PIN码,无论该证书是否需要PIN码。就目前而言,我提出的唯一解决方案是:

    • 提出设置用户确定PIN码的方法
    • 检查执行CryptSetProvParam(使用dwParam 32-KeyExchangePin)时是否发生异常,如果发生异常,请通过Marshal.GetLastWin32Error()检查异常值
    • 根据错误值确定证书的私钥不需要PIN码
    我知道这个解决方案很肮脏,但可能会帮助一些人


    然而,我非常希望看到基于加密API的“正确”解决方案。

    使用windows资源管理器第一次使卡工作。当您设置驱动程序时,许多问题都会自动处理。阅读供应商用户手册。一旦卡与资源管理器一起使用,您就可以将其与c#代码一起使用。Windows资源管理器将解锁该卡,然后您可以进行读写操作。智能卡有不同的寻址模式和数据大小(8,16,32,64)。因此,请确保您可以使用windows进行写操作,并使用c#进行读操作(反之亦然)。然后编写代码以在c#中解锁。您需要知道解锁卡的大小。
    这非常慢
    ——有多慢?您可以考虑使用Win32互操作来查询证书属性,读取提供程序名称,然后查询提供程序。