繁体   English   中英

在多个 CMS 签名中缓存 PIN

[英]Caching PIN in multiple CMS Signatures

好吧,我在这里找到的大多数问题/答案都是关于不缓存智能卡 PIN,这与我正在寻找的情况相反。

我们有一个控制台应用程序,可以对多个哈希进行签名。 为此,我们使用Pkcs.CmsSigner,因为我们需要在服务器端验证签名的哈希值。

通常,智能卡的 PIN 应自动缓存在每个进程的 CSP 中,在 Windows 7 中也是如此,但如果我们在 W10 中运行我们的代码,则不会。 我们还支持 CNG 和非 CNG 证书。

我们用来签名的方法如下:

public string SignX509(string data, bool chkSignature, string timestampServer, X509Certificate2 selectedCertificate)
{

    CmsSigner oSigner = null;
    SignedCms oSignedData = null;
    string hashText = String.Empty;

    try
    {
        if (chkSignature)
        {
            oSigner = new CmsSigner();

            oSigner.Certificate = selectedCertificate;

            byte[] arrDataHashed = HashSHA1(data);

            // hash the text to sign
            ContentInfo info = new ContentInfo(arrDataHashed);

            // put the hashed data into the signedData object
            oSignedData = new SignedCms(info);

            if (string.IsNullOrEmpty(timestampServer)) {
                oSigner.SignedAttributes.Add(new Pkcs9SigningTime(DateTime.Now));
            }
            else {
                TimeStampToken tsToken = GetTSAToken(arrDataHashed, timestampServer);

                AsnEncodedData timeData = new Pkcs9AttributeObject(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificate.Id, tsToken.GetEncoded());
                oSigner.UnsignedAttributes.Add(timeData);
                oSigner.SignedAttributes.Add(new Pkcs9SigningTime(tsToken.TimeStampInfo.GenTime.ToLocalTime()));
            }

            // sign the data
            oSignedData.ComputeSignature(oSigner, false);

            hashText = Convert.ToBase64String(oSignedData.Encode());
            
        }
        else 
        {
            // just clean the hidden hash text
            hashText = String.Empty;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("ERRNO [" + ex.Message + " ]");
        return null;
    }

    return hashText;
}

到目前为止我们尝试过的:

  1. 使用 RSACryptoServiceProvider 在 CSP 中显式持久化密钥
RSACryptoServiceProvider key = (RSACryptoServiceProvider)cmsSigner.Certificate.PrivateKey;
key.PersistKeyInCsp = true; 

如果我们使用SignHash方法,这会起作用,但正如我之前所说,我们需要验证已签名的数据服务器端,而我们无权访问证书,因此我们需要一个 PKCS 信封。 如果我设置这个 bool 并使用 CMS 代码签名,则行为是相同的。

  1. 以编程方式设置 PIN

另一种尝试是根据以下答案通过 CryptoContext 以编程方式设置 PIN:

private void SetPinForPrivateKey(X509Certificate2 certificate, string pin) {

    if (certificate == null) throw new ArgumentNullException("certificate");
    var key = (RSACryptoServiceProvider)certificate.PrivateKey;

    var providerHandle = IntPtr.Zero;
    var pinBuffer = System.Text.Encoding.ASCII.GetBytes(pin);

    // provider handle is implicitly released when the certificate handle is released.
    SafeNativeMethods.Execute(() => SafeNativeMethods.CryptAcquireContext(ref providerHandle,
                                    key.CspKeyContainerInfo.KeyContainerName,
                                    key.CspKeyContainerInfo.ProviderName,
                                    key.CspKeyContainerInfo.ProviderType,
                                    SafeNativeMethods.CryptContextFlags.Silent));

    SafeNativeMethods.Execute(() => SafeNativeMethods.CryptSetProvParam(providerHandle,
                                    SafeNativeMethods.CryptParameter.KeyExchangePin,
                                    pinBuffer, 0));
    SafeNativeMethods.Execute(() => SafeNativeMethods.CertSetCertificateContextProperty(
                                    certificate.Handle,
                                    SafeNativeMethods.CertificateProperty.CryptoProviderHandle,
                                    0, providerHandle));
}

通过这种方法,我可以通过以编程方式设置 PIN 来禁用 PIN 提示 这里的问题是我必须第一次读取 PIN 码,以便我可以在后续签名中设置它。

我尝试使用CryptoGetProvParam和 dwParam PP_ADMIN_PIN 和 PP_KEYEXCHANGE_PIN 从提示中读取 PIN 但没有运气。 我的两个猜测是:

  1. 我没有在正确的时间或方式阅读
  2. CMS 在内部使用不同的处理程序

问题 1:

有什么方法可以读取 Windows 提示中设置的 PIN 码?

W10提示

问题2:

如果无法读取 PIN,还有其他方法可以强制 PIN 缓存吗?

现在才意识到这个问题仍然没有答案,尽管我们设法绕过了整个“从 Windows 提示中读取 PIN”的问题。

这种方法不能回答我的第一个问题,但我会回答第二个问题。

智能卡 CSP 提供程序中存在一个错误,该错误会禁用对SignHash所有请求的 PIN 缓存,即使它们是在同一进程中发出的。

智能卡提供商有一个 SDK,它公开一些智能卡操作,其中之一是验证智能卡 PIN 的操作。

我们最终做的是创建一个简单的 WPF 窗口,该窗口请求用户的 PIN 并使用 SDK 来验证 PIN。 如果正确,我们使用我在原始问题中发布的方法来强制 PIN 缓存:

另一个尝试是根据以下答案通过 CryptoContext 以编程方式设置 PIN:

 private void SetPinForPrivateKey(X509Certificate2 certificate, string pin) { if (certificate == null) throw new ArgumentNullException("certificate"); var key = (RSACryptoServiceProvider)certificate.PrivateKey; var providerHandle = IntPtr.Zero; var pinBuffer = System.Text.Encoding.ASCII.GetBytes(pin); // provider handle is implicitly released when the certificate handle is released. SafeNativeMethods.Execute(() => SafeNativeMethods.CryptAcquireContext(ref providerHandle, key.CspKeyContainerInfo.KeyContainerName, key.CspKeyContainerInfo.ProviderName, key.CspKeyContainerInfo.ProviderType, SafeNativeMethods.CryptContextFlags.Silent)); SafeNativeMethods.Execute(() => SafeNativeMethods.CryptSetProvParam(providerHandle, SafeNativeMethods.CryptParameter.KeyExchangePin, pinBuffer, 0)); SafeNativeMethods.Execute(() => SafeNativeMethods.CertSetCertificateContextProperty( certificate.Handle, SafeNativeMethods.CertificateProperty.CryptoProviderHandle, 0, providerHandle)); }

有了这个,我们只能在签署多个哈希时请求 PIN 一次,直到智能卡提供商修复他们这边的错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM