C# - кэширование ПИН-кода в нескольких сигнатурах CMS - PullRequest
0 голосов
/ 23 марта 2020

Ну, большинство вопросов / ответов, которые я нашел здесь, касаются не кэширования PIN-кода смарт-карты, что является противоположным случаем того, что я ищу.

У нас есть консольное приложение, которое подписывает несколько хешей. Для этого мы используем Pkcs.CmsSigner , потому что нам нужно проверить подписанные хеши на стороне сервера.

Обычно ПИН-код смарт-карты должен автоматически кэшироваться в 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; 

Это работает, если мы используем метод SignHa sh, но, как я уже говорил, нам нужно проверить подписали данные на стороне сервера, и у нас нет доступа к сертификату, поэтому нам нужен конверт PKCS. Если я установлю это bool и подпишу, используя код CMS, то поведение будет таким же.

Установка PIN-кода программно

Другой попыткой была установка PIN-кода программно через CryptoContext на основе этого ответа :

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-код в первый раз, чтобы я мог установить его в последующих подписях.

Я пытался прочитать PIN-код из приглашения, используя CryptoGetProvParam с dwParam PP_ADMIN_PIN и PP_KEYEXCHANGE_PIN, но безуспешно. Вот мои две догадки:

  1. Я не читаю в нужное время или в нужном направлении
  2. CMS использует другой обработчик внутри

Вопрос 1:

Можно ли прочитать PIN-код, указанный в приглашении Windows?

W10Prompt

Вопрос 2:

Если считывание ПИН-кода невозможно, есть ли другой способ форсировать кеширование ПИН-кода?

...