簡體   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