【问题标题】:How can I set PIN for a X509Certificate2 programmatically?如何以编程方式为 X509Certificate2 设置 PIN?
【发布时间】:2021-05-18 17:26:31
【问题描述】:

我需要每天向网络服务发送数据,所以我制定了一个运行我的代码的计划任务。问题是网络服务需要一个带有 PIN 码的证书。我已附上证书,但找不到设置 PIN 的方法,因此每次手动输入时都会显示一个弹出窗口。

这是我的证书代码:

private void SendData(string data)
    {
        using (SerWSService webService = new SerWSService())
        {
            string certificateSN = "serial number for the certificate";
            webService.ClientCertificates.Add(FindCertificate(certificateSN));

            webService.SendData(data);
        }
    }

private X509Certificate2 FindCertificate(string certserial)
    {
        X509Certificate2 WPE_UserCert = null;
        X509Store wstore = default(X509Store);
        wstore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        wstore.Open(OpenFlags.ReadOnly);
        var wcerts = wstore.Certificates;
        foreach (var wcert in wcerts)
        {
            if (wcert.SerialNumber.ToUpper() == certserial.Replace(" ", "").ToUpper())
            {
                WPE_UserCert = wcert;
                break;
            }
        }
        wstore.Close();

        if (WPE_UserCert != null)
        {
            //TO DO: add PIN code to certificate

        }

        return WPE_UserCert;
    }

有什么方法可以将 PIN 设置为证书?

【问题讨论】:

    标签: c# certificate


    【解决方案1】:

    不,因为证书没有 PIN; (私人)密钥。

    如果您找到带有私钥的证书并将该证书传递给需要统一对的类(例如 SslStream、HttpClient),那么就没有真正/好的解决方案。

    如果你自己使用私钥,你还有一些余地:

    using (RSA rsa = cert.GetRSAPrivateKey())
    {
        RSACng rsaCng = rsa as RSACng;
        RSACryptoServiceProvider rsaCsp = rsa as RSACryptoServiceProvider;
    
        if (rsaCng != null)
        {
            // Set the PIN, an explicit null terminator is required to this Unicode/UCS-2 string.
    
            byte[] propertyBytes;
    
            if (pin[pin.Length - 1] == '\0')
            {
                propertyBytes = Encoding.Unicode.GetBytes(pin);
            }
            else
            {
                propertyBytes = new byte[Encoding.Unicode.GetByteCount(pin) + 2];
                Encoding.Unicode.GetBytes(pin, 0, pin.Length, propertyBytes, 0);
            }
    
            const string NCRYPT_PIN_PROPERTY = "SmartCardPin";
    
            CngProperty pinProperty = new CngProperty(
                NCRYPT_PIN_PROPERTY,
                propertyBytes,
                CngPropertyOptions.None);
    
            rsaCng.Key.SetProperty(pinProperty);
        }
        else if (rsaCsp != null)
        {
            // This is possible, but painful.
            // Copy out the CspKeyContainerInfo data into a new CspParameters,
            // build the KeyPassword value on CspParameters,
            // Dispose() the existing instance,
            // and open a new one to replace it.
            //
            // But if you really called GetRSAPrivateKey() and it has returned an RSACng for
            // your device once, it pretty much will forever (until the next
            // new RSA type for Windows is invented... at which point it still
            // won't return an RSACryptoServiceProvider).
        }
        else
        {
            // No other built-in RSA types support setting a PIN programmatically.
        }
    
        // Use the key here.
        // If you needed to return it, don't put it in a using :)
    }
    

    【讨论】:

    • Jeremy (bartonjs),前几天我已经 asked 你了,现在我找到了这个答案,谢谢!但是...在Key Storage Property Identifiers 页面,这是关于NCRYPT_PIN_PROMPT_PROPERTY 的文字:“This value is not supported.”,正如名字所说的“提示”,我认为这是为了显示或不显示询问 PIN 的提示窗口...这真的是通知密钥 PIN 的正确属性吗?
    • 我实际上认为NCRYPT_PIN_PROPERTY 会是答案,之后我怀疑NCRYPT_SECURE_PIN_PROPERTY 是否是答案,但没有成功。但是我没有为字节数组设置空终止符。而且我不确定是否必须创建RSACng 的新实例,就像我们必须创建RSACryptoServiceProvider 的新实例一样,但您已经在这里回答了。我试图用葡萄牙语回答某人:InvalidCastException: Unable to cast object of type 'System.Security.Cryptography.RSACng'
    • @PedroGaspar 不,NCRYPT_PIN_PROPERTY 是,RSACng 没有 SetProperty 方法。修复了答案中的错误。
    • 对于它的价值,这至少在 Windows 10 上不起作用。它在 setProperty 调用上引发“参数不正确”错误。
    【解决方案2】:

    在 CSP 私钥的情况下,使用 CryptAcquireCertificatePrivateKey 获取 CryptoProv 句柄,然后使用 CryptSetProvParam(h,PP_SIGNATURE_PIN,pin,0) 设置 PIN。

    【讨论】:

      猜你喜欢
      • 2020-11-15
      • 1970-01-01
      • 1970-01-01
      • 2011-11-26
      • 2014-10-18
      • 2019-10-09
      • 2020-01-02
      • 1970-01-01
      • 2017-10-20
      相关资源
      最近更新 更多