CryptoPro / corefx

This repo contains the .NET Core foundational libraries, called CoreFX. It includes classes for collections, file systems, console, XML, async and many others. We welcome contributions.
https://github.com/dotnet/core
MIT License
27 stars 7 forks source link

`get_Gost3411_2012_256()` Method not found #29

Closed kanybekov closed 4 years ago

kanybekov commented 4 years ago

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

Пытаюсь запустить приложение под линуксом.

  1. Добавил пропатченный NetStandard в nuget-фид.
  2. Выполнил build приложения.
  3. .dll и .pdb файл проекта, а также dll сторонних пакетов (по сути, все содержимое папки publish) положил в папку с рантаймом, которая была скачана из репозитория - файл runtime-debug-linux.zip
  4. В папке с рантаймом запускаю dll моего приложения.

Вижу такую ошибку:

{ "date": "2020-07-29 06:44:33.4152", "level": "ERROR", "logger": "CryptographyService", "message": "Method not found: 'System.Security.Cryptography.HashAlgorithmName System.Security.Cryptography.HashAlgorithmName.get_Gost3411_2012_256()'.", "eventProperties": {  }, "exception": "System.MissingMethodException: Method not found: 'System.Security.Cryptography.HashAlgorithmName System.Security.Cryptography.HashAlgorithmName.get_Gost3411_2012_256()'.\n  
at Internal.Cryptography.PkcsHelpers.GetDigestAlgorithm(String oidValue, Boolean forVerification)\n  
at System.Security.Cryptography.Pkcs.SignerInfo.GetDigestAlgorithm() in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignerInfo.cs:line 737\n  
at System.Security.Cryptography.Pkcs.SignerInfo.PrepareDigest(Boolean compatMode) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignerInfo.cs:line 510\n  
at System.Security.Cryptography.Pkcs.SignerInfo.VerifySignature(CmsSignature signatureProcessor, X509Certificate2 certificate, Boolean compatMode) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignerInfo.cs:line 698\n  
at System.Security.Cryptography.Pkcs.SignerInfo.Verify(X509Certificate2Collection extraStore, X509Certificate2 certificate, Boolean verifySignatureOnly) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignerInfo.cs:line 647\n  
at System.Security.Cryptography.Pkcs.SignerInfo.CheckSignature(X509Certificate2Collection extraStore, Boolean verifySignatureOnly) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignerInfo.cs:line 415\n  
at System.Security.Cryptography.Pkcs.SignedCms.CheckSignatures(SignerInfoCollection signers, X509Certificate2Collection extraStore, Boolean verifySignatureOnly) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignedCms.cs:line 595\n  
at System.Security.Cryptography.Pkcs.SignedCms.CheckSignature(X509Certificate2Collection extraStore, Boolean verifySignatureOnly) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignedCms.cs:line 578\n  
at System.Security.Cryptography.Pkcs.SignedCms.CheckSignature(Boolean verifySignatureOnly) in \/home\/appveyor\/projects\/corefx\/src\/System.Security.Cryptography.Pkcs\/src\/System\/Security\/Cryptography\/Pkcs\/SignedCms.cs:line 569\n  
at SignatureVerifier.Domain.Services.CryptographyService.VerifyDetachedSignature(Byte[] signedData, Byte[] signature) in \/app\/SignatureVerifier\/SignatureVerifier.Domain\/Services\/CryptographyService.cs:line 66" }

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

Fasjeit commented 4 years ago

Если собирается корректно - значит в рантайме подцеплятеся не та версия рантайма дотнета. Т.е. собрался с версией, которая знала про ГОСТ, а вот пытается запуситься с версией, которая про ГОСТ не знаеет.

На текущий момент мы поддерживаем только self-contained сценарий использования рантайма, когда рантайм поставляется локально вместе с собранным проектом в той же папке. Т.е. после сборки такого проекта рантайм должен будет расположен вместе с получившимися сборками. Пример такого проекта можно посмотреть тут. Сам рантайм для сборки подгружается из Nuget пакетов (см инструкцию), за исключением сборок, не входящий в пакет (Pkcs и Xml). При этом должны быть установлены указанные в интрукции версии "честного" рантайма от ms. Если указанные версии не установлены - возможно появление ошибки аналогичной вашей, когда для запуса используется рантайм отличный от того, что использовался при сборке.

Итого:

  1. Попробовать запустить и собрать тестовый проект DotnetSampleProject. Убедиться, что установлены указанные версии рантайма и sdk и в csproj указанна корректная версия nuget пакета рантайма (Microsoft.Private.CoreFx.NETCoreApp),
  2. В случае успеха попробовать запустить ваш проект, убедившись, что корректно указана версия рантайма, и что проект собирается как self-contained.
kanybekov commented 4 years ago

Спасибо за ответ.

Если собирается корректно - значит в рантайме подцеплятеся не та версия рантайма дотнета. Т.е. собрался с версией, которая знала про ГОСТ, а вот пытается запуситься с версией, которая про ГОСТ не знаеет.

Запутался в рантаймах. собрался с версией, которая знала про ГОСТ, это же про версию пропатченного рантайма, потому что я не совсем понимаю, как оригинальный рантайм может знать про ГОСТ ?


P.S. Запускаю своё тестовое приложение, которое получает список сертификатов из хранилища, двумя способами: по-своему и как описано в ридми DotnetSampleProject. Самое интересное, что результаты совершенно разные, при этом, первый способ корректно выводит сертификат, который я установил в контейнере до этого, а второй способ выводит какие-то непонятные сертификаты.


P.P.S. Такая ошибка может возникать из-за неустановленного КриптоПро CSP?

Fasjeit commented 4 years ago

Оригинальный рантайм про гост знать и не может и с ним не заработает. Но иногда (как минимум, если не установлены нужны версии оригинального рантайма) подкладывается оригинальный, вместо патченного, и всё падает.

Начните с запуска и тестирования кода в DotnetSampleProject, Там должно всё работать, если указанны корректные пути и установлены корректные версии.

Если не установлен КриптоПро CSP ошибку скорее всего будет в невозможности найти библитеку на unix, или криптографичская ошибка на Windows.

kanybekov commented 4 years ago

Начните с запуска и тестирования кода в DotnetSampleProject, Там должно всё работать, если указанны корректные пути и установлены корректные версии.

Запускаю DotnetSampleProject: вижу сообщение Insert carrier to open container CLR{0F871D0D-5491-48BA-94DD-715F73280FFD}

Я приношу свои извинения, если мои вопросы выходят за рамки issue гитхаба, но хочется уже наконец запустить приложение.

Fasjeit commented 4 years ago

Это уже неплохо. CSP просит указать хранилище для контейнера в интерактивном режиме (аналог окошка в windows) при импорте сертификата. Это ожидаемо.

Если до этого этапа дошли - уже можно пробовать запускать свой внутри проекта. Далее попробуйте например отерыть установленный сертификат из хранилища.

kanybekov commented 4 years ago

Изменил код Program.cs, чтобы он загружал мой гостовский сертификат из хранилища и проверял цепочку сертификата. Работает без ошибок.

Добавил код для генерации и проверки открепленной подписи, вижу ошибку:

Unhandled exception. System.Security.Cryptography.CryptographicException: Could not determine signature algorithm for the signer certificate.
   at System.Security.Cryptography.Pkcs.CmsSigner.Sign(ReadOnlyMemory`1 data, String contentTypeOid, Boolean silent, X509Certificate2Collection& chainCerts) in /home/appveyor/projects/corefx/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs:line 266
   at System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner signer, Boolean silent) in /home/appveyor/projects/corefx/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs:line 323
Fasjeit commented 4 years ago

Путь до System.Security.Cryptography.Pkcs в проекте указан корректно? Нужен путь до папки runtime (из архива runtime-debug-linux.zip), содержащую данную сборку.

kanybekov commented 4 years ago

Вот содержимое файла .csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <RuntimeFrameworkVersion>3.1.3</RuntimeFrameworkVersion>
    <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
    <!-- make self-contained -->
    <PackageConflictPreferredPackages>Microsoft.Private.CoreFx.NETCoreApp;runtime.win-x64.Microsoft.Private.CoreFx.NETCoreApp;runtime.linux-x64.Microsoft.Private.CoreFx.NETCoreApp;$(PackageConflictPreferredPackages)</PackageConflictPreferredPackages>
  </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.Private.CoreFx.NETCoreApp" Version="4.7.0-dev.20163.1" />
    </ItemGroup>
    <ItemGroup>
      <Reference Include="System.Security.Cryptography.Pkcs">
        <HintPath>..\runtime_debug\System.Security.Cryptography.Pkcs.dll</HintPath>
      </Reference>
      <Reference Include="System.Security.Cryptography.Xml">
        <HintPath>..\runtime_debug\System.Security.Cryptography.Xml.dll</HintPath>
      </Reference>
    </ItemGroup>
</Project>

Соответственно, на уровень выше в папке runtime_debug есть файлы из архива runtime-debug-linux.zip. Я сравнил размеры файлов Pkcs.dll, они совпадают.

Fasjeit commented 4 years ago

Проверьте, что сертификат установлен с привязкой к закрытому ключу, и что закрытый ключ виден под в объекте сертификата (например под отладчиком). Вот такой тестик должен работать, с заменой сертификата на ваш.

    public static void Do()
    {
        // The dataToSign byte array holds the data to be signed.
        ContentInfo contentInfo = new ContentInfo(new byte[] {0});

        // Create a new, detached SignedCms message.
        SignedCms signedCms = new SignedCms(contentInfo, true);

        using(var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
        {
            store.Open(OpenFlags.ReadOnly);
            var cert = store.Certificates.Find(X509FindType.FindByThumbprint, "9FE0BBF23FB31596AC6AAEB85C8C6734A4D20AF4", false)[0];

             // Определяем подписывающего, объектом CmsSigner.
            CmsSigner cmsSigner = new CmsSigner(cert);

            // Sign the message.
            signedCms.ComputeSignature(cmsSigner);
        }
        // Encode the message.
        byte[] myCmsMessage = signedCms.Encode();
    }
kanybekov commented 4 years ago

Задержался, сейчас запустил этот код, вижу такую ошибку

Unhandled exception. System.DllNotFoundException: Unable to load shared library 'ncrypt.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libncrypt.dll: cannot open shared object file: No such file or directory
   at Interop.NCrypt.NCryptGetProperty(SafeNCryptHandle hObject, String pszProperty, Void* pbOutput, Int32 cbOutput, Int32& pcbResult, CngPropertyOptions dwFlags)
   at Internal.Cryptography.Helpers.GetPropertyAsIntPtr(SafeNCryptHandle ncryptHandle, String propertyName, CngPropertyOptions options) in C:\projects\corefx\src\System.Security.Cryptography.Cng\src\Internal\Cryptography\Helpers.cs:line 146
   at System.Security.Cryptography.CngKey.Open(SafeNCryptKeyHandle keyHandle, CngKeyHandleOpenOptions keyHandleOpenOptions) in C:\projects\corefx\src\System.Security.Cryptography.Cng\src\System\Security\Cryptography\CngKey.OpenHandle.cs:line 30
   at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
   at Internal.Cryptography.Pal.CertificatePal.GetGost3410_2012_256PrivateKey()
   at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
   at System.Security.Cryptography.Pkcs.CmsSigner..ctor(SubjectIdentifierType signerIdentifierType, X509Certificate2 certificate, AsymmetricAlgorithm privateKey) in C:\projects\corefx\src\System.Security.Cryptography.Pkcs\src\System\Security\Cryptography\Pkcs\CmsSigner.cs:line 96
   at System.Security.Cryptography.Pkcs.CmsSigner..ctor(SubjectIdentifierType signerIdentifierType, X509Certificate2 certificate) in C:\projects\corefx\src\System.Security.Cryptography.Pkcs\src\System\Security\Cryptography\Pkcs\CmsSigner.cs:line 65
   at System.Security.Cryptography.Pkcs.CmsSigner..ctor(X509Certificate2 certificate) in C:\projects\corefx\src\System.Security.Cryptography.Pkcs\src\System\Security\Cryptography\Pkcs\CmsSigner.cs:line 50
   at DotnetSample.Program.Do() in /crypto_pro/api_test/Program.cs:line 79
   at DotnetSample.Program.Main(String[] args) in /crypto_pro/api_test/Program.cs:line 43
Fasjeit commented 4 years ago

Странно. На Linux ожидаемое поведение ошибка CLR/System.PlatformNotSupportedException в

System.Security.Cryptography.Cng.dll!Microsoft.Win32.SafeHandles.SafeNCryptHandle.SafeNCryptHandle() Line 5 (/home/fasjeit/git/corefx/artifacts/obj/System.Security.Cryptography.Cng/netcoreapp-Debug/System.Security.Cryptography.Cng.notsupported.cs:5)
System.Security.Cryptography.Cng.dll!Microsoft.Win32.SafeHandles.SafeNCryptKeyHandle.SafeNCryptKeyHandle() Line 13 (/home/fasjeit/git/corefx/artifacts/obj/System.Security.Cryptography.Cng/netcoreapp-Debug/System.Security.Cryptography.Cng.notsupported.cs:13)
System.Security.Cryptography.X509Certificates.dll!Internal.Cryptography.Pal.CertificatePal.TryAcquireCngPrivateKey(Internal.Cryptography.Pal.Native.SafeCertContextHandle certificateContext, out System.Security.Cryptography.CngKeyHandleOpenOptions handleOptions) Line 381 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs:381)
System.Security.Cryptography.X509Certificates.dll!Internal.Cryptography.Pal.CertificatePal.GetPrivateKey<System.Security.Cryptography.Gost3410_2012_256>(System.Func<System.Security.Cryptography.CspParameters, System.Security.Cryptography.Gost3410_2012_256> createCsp, System.Func<System.Security.Cryptography.CngKey, System.Security.Cryptography.Gost3410_2012_256> createCng) Line 319 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs:319)
System.Security.Cryptography.X509Certificates.dll!Internal.Cryptography.Pal.CertificatePal.GetGost3410_2012_256PrivateKey() Line 89 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs:89)
System.Security.Cryptography.X509Certificates.dll!System.Security.Cryptography.X509Certificates.X509Certificate2.PrivateKey.get() Line 226 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs:226)
System.Security.Cryptography.Pkcs.dll!System.Security.Cryptography.Pkcs.CmsSigner.CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.AsymmetricAlgorithm privateKey) Line 96 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs:96)
System.Security.Cryptography.Pkcs.dll!System.Security.Cryptography.Pkcs.CmsSigner.CmsSigner(System.Security.Cryptography.Pkcs.SubjectIdentifierType signerIdentifierType, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) Line 65 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs:65)
System.Security.Cryptography.Pkcs.dll!System.Security.Cryptography.Pkcs.CmsSigner.CmsSigner(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) Line 50 (/home/fasjeit/git/corefx/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs:50)
DotnetSampleProject.dll!CmsTest.Do() Line 20 (/home/fasjeit/git/DotnetCoreSampleProject/CmsTest.cs:20)
DotnetSampleProject.dll!DotnetSample.Program.Main(string[] args) Line 19 (/home/fasjeit/git/DotnetCoreSampleProject/Program.cs:19)
[Native to Managed Transition] (Unknown Source:0)

После чего происходит зануление возвращаемого значения ncryptKey в TryAcquireCngPrivateKey и вызов ветки csp в методе private T GetPrivateKey<T>(Func<CspParameters, T> createCsp, Func<CngKey, T> createCng) where T : AsymmetricAlgorithm в System.Security.Cryptography.X509Certificates\src\Internal\Cryptography\Pal.Windows\CertificatePal.PrivateKey.cs.

https://github.com/CryptoPro/corefx/blob/f43bd3af06ac383d51ae7e2eb07c5ad893e404d3/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs#L316-L347

В вашем случае почему то прошло дальше и сломалось на ветке CNG в попытке открыть CNG ключ.

Уточните пожалуйста, на какой конкретно ОС воспроизводится данное поведение? Воспроизводится ли данное поведение на Windows с тем же сертификатом?

ps. Если интересно самостоятельно подебажить указанное место - при использование debug пакета с рантаймом - достаточно переместить pdb файлы из папки runtime (той, до которой указан путь для сборкок pkcs и xml) в папку /bin/Debug/netcoreapp3.1/linux-x64 или аналогичную для вашего проекта. Символы должны затянуться vscode автоматически при отладке вашего проекта.

tolyanich commented 4 years ago

Using latest version from master resolves this issue.