[英]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.