[英]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;
}
RSACryptoServiceProvider key = (RSACryptoServiceProvider)cmsSigner.Certificate.PrivateKey;
key.PersistKeyInCsp = true;
如果我们使用SignHash方法,这会起作用,但正如我之前所说,我们需要验证已签名的数据服务器端,而我们无权访问证书,因此我们需要一个 PKCS 信封。 如果我设置这个 bool 并使用 CMS 代码签名,则行为是相同的。
另一种尝试是根据以下答案通过 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 但没有运气。 我的两个猜测是:
有什么方法可以读取 Windows 提示中设置的 PIN 码?
如果无法读取 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.