AlexMAS / GostCryptography

.NET driver for ViPNet CSP and CryptoPro CSP
MIT License
132 stars 42 forks source link

Нет возможности указать пароль контейнера закрытого ключа при создании открепленной подписи #16

Open LeonxPRO opened 5 years ago

LeonxPRO commented 5 years ago

Использую GostCryptography, для создания открепленной (CMS Sign, PKCS7) подписи. Пользуюсь примером из тестового проекта "SignedCmsSignTest", идущего вместе с исходниками. Никак не получается программно указать пароль контейнера VipNet для создания автоматизации ЦП. Для обычного шифрования/подписи данных проблем не возникает, но в случае создания открепленной подписи, в классах GostSignedCms и NET CmsSigner нет возможности указать пароль контейнера приватного ключа или Алгоритм подписи с уже заданным ключом.

Даже когда использую конструктор public CmsSigner (CspParameters parameters) и в CspParameters, заполненным параметрами из сертификата добавляю SecureString с необходимым паролем и флагом подавления окна cspKeyParams.Flags = CspProviderFlags.NoPromp - все равно во время выполнения VipNet вываливает диалоговое окно с предложением ввести пароль контейнера.

var cspKeyParams = certificate.GetPrivateKeyInfo();
cspKeyParams.Flags = CspProviderFlags.NoPrompt;
cspKeyParams.KeyPassword = secStr;
var signer = new CmsSigner(cspKeyParams);

Судя по исходникам NET эти два параметра CspParameters просто игнорируются в недрах класса CmsSigner. Можно ли добавить какую-либо возможность использовать в библиотеке пароль контейнера в данном случае? P.S. Спасибо за библиотеку!

DPonomarchuk commented 5 years ago

Присоединяюсь к вопросу

AlexMAS commented 5 years ago

Здравствуйте.

Класс GostSignedCms реализован на базе стандартного SignedCms, который не предоставляет нужную функциональность и каких-либо способов изменения поведения. Могу предложить обходной вариант и попытаться получить доступ к контейнеру с секретным ключем на время выполнения подписи, например, так:

private static byte[] SignMessage(X509Certificate2 certificate, SecureString password, byte[] message)
{
    using (var privateKey = (Gost_R3410_2012_512_AsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm())
    {
        privateKey.SetContainerPassword(password);

        // Далее логика подписи...

        var signedCms = new GostSignedCms(new ContentInfo(message), true);
        var signer = new CmsSigner(certificate);
        signer.IncludeOption = X509IncludeOption.EndCertOnly;
        signedCms.ComputeSignature(signer);
        return signedCms.Encode();
    }
}

P.s. К сожалению, не смог проверить работоспособность этого подхода, т.к. на машине не установлен CSP. Отпишитесь, пожалуйста, получилось или нет решить проблему.

LeonxPRO commented 5 years ago

Спасибо за ответ. но такой способ не помог. В качестве логики подписи использовал: var dummySign = privateKey.CreateSignature(message, privateKey.CreateHashAlgorithm());, получил байтовый массив без проблем, но на вызове signedCms.ComputeSignature(signer); опять захотел пароль.

AlexMAS commented 5 years ago

Выяснилось, что на данный момент возможности программно указать пароль к контейнеру закрытого ключа на данный момент нет. Текущая реализация SignedCms в .NET Framework полностью основана на unmanaged-коде и не использует высокоуровневые абстрации (вроде AsymmetricAlgorithm). Также API класса SignedCms не предполагает установки ассимитричного ключа (через свойство или конструктор). Если вышеуказанный трюк не помогает (а у меня он тоже не работает), значит, другого способа нет, кроме как сохранить пароль к ключу.

То, о чем вы спрашиваете, только планируется в .NET Core 3. Возможно, появится и в очередной версии .NET Framework.

LeonxPRO commented 5 years ago

Спасибо, что подтвердили мои опасения ) Мне надо что-то делать дальше с этим issue?

AlexMAS commented 5 years ago

Да пока пусть будет открыта. :)