CryptoPro / libcore

44 stars 0 forks source link

Проблема при настройке SSL-сертификата в Kestrel (чтение из pfx) #21

Closed mevelop closed 1 year ago

mevelop commented 1 year ago

Стенд

Проблема

После вызова LibCore.Initializer.Initialize();

и выбора сертификата RSA / ГОСТ для Kestrel с помощью builder.WebHost.UseKestrel(x => x.ConfigureHttpsDefaults(y => y.ServerCertificate = GetCert()));

запросы не проходят с ошибкой после успешного старта приложения: New password:Unhandled exception. LibCore.Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The keyset is not defined.

или приложение не стартует с ошибкой: System.ComponentModel.Win32Exception (0x80090307): Unknown error -2146893049

Демо

Прикладываю DemoKestrelSsl.zip с демонстрацией проблемы с 5ю вариациями метода GetCert():

  1. GetCert_1 - RSA сертификат в обычном состоянии дотнета
  2. GetCert_2 - RSA сертификат со включенным LibCore
  3. GetCert_3 - RSA сертификат со включенным LibCore и установкой CspNoPersistKeySet
  4. GetCert_4 - ГОСТ сертификат со включенным LibCore
  5. GetCert_5 - ГОСТ сертификат со включенным LibCore и установкой CspNoPersistKeySet

P.S:

  1. Невозможность выбора ни одного сертификата из RSA/ГОСТ так же наблюдается в вашем проекте corefx, но мы решили проверить еще на этой версии. Если проще или удобнее помочь с данным вопросом в том проекте, то тоже подходит :)
  2. Данный функционал в чем-то поможет заменить ваш проект nginx-gost, особенно актуально при использовании YARP.
Fasjeit commented 1 year ago

3 и 4 вариант точно не будет работать в текущей архитектуре. Почему падает 2 - посмотрим.

Не пробовали вариант установки сертификата в хранилище и чтения из него? Не уверен, что сценарий TLS + in memory работает для сертификата....

Bykiev commented 1 year ago

А в ARM вообще библиотека работает?

Fasjeit commented 1 year ago

А в ARM вообще библиотека работает?

В явном виде не поддерживаем, но может что то работать. Целевые ос - Windows 10-11 + server, Debian (Ubuntu, Astra), x64. Всё остальное - вне текущего приоритета, но смотрим каждый случай. Если можем безболезненно починить - чиним.

В этом году, надеюсь, проведём некоторую переработку и, возможно, расширим число целевых платформ.

Fasjeit commented 1 year ago

Сценарий 2 - csp пытается создать контейнер и запрашивает пароль при установке, отсюда и ошибка. Не уверен, что сейчас хотим поддерживать безконтейнерный серверный tls. Стоит попробовать с честной установкой сертификатов в хранилище.

Для RSA я бы не инициализировал исправления для System.Net, если нет гостового взаимодействия по TSL.

mevelop commented 1 year ago

В этом и проблема. Мы не можем честно добавить в хранилище сертификатов нужный сертификат автоматически при сборке docker, потому что csp просит новый пароль для контейнера в интерактивном режиме, только если руками поднимать контейнер и вводить с клавиатуры ответы на запросы, но получается в это время kestrel не может стартовать, потому что его потом не перенастроить нормально, поэтому запуск только вручную, а это не путь docker :) Если подскажете способ, как добавить в хранилище скриптами автоматом, то мы проверим взятие оттуда.

Вообще нас 5-й вариант интересует, конечно. Если необходимо работать на х64, без проблем, просто скажите, что дело в arm.

Fasjeit commented 1 year ago

Установить сертификаты без окошек можно через контейнеры.

Устанавливаете сертификат на какой либо машине в ручном режиме, указываете установку контейнера в папку. Сертификат, из которого устанавливаете контейнер, также будет добавлен в этот контейнер.

После этого можете копировать указанный контейнер на целевую машину по пути /var/opt/cprocsp/keys/{user}/:

cp -r ./G2001256.000 /var/opt/cprocsp/keys/{user}/

где G2001256.000 - папка с контейнером ключа, {user} - имя пользователя, из под которого стартует сервис

После чего устанавливаете сертификат из контейнера:

/opt/cprocsp/bin/amd64/csptest  -absorb -certs -provtype 80 -pattern "G2012256"

где G2001256 - имя контейнера ключа, 80 - тип провайдера.

В контейнере для CI у нас данный сценарий прекрасно работает.

По поводу пятого сценария - если подразумевается просто гостовый TSL - то пробуйте через установку сертификата, как указанно выше. По поводу загрузки серта для TLS из памяти - скорее всего, как указано выше, не заработает.

mevelop commented 1 year ago

Пробуем снова исследовать вопрос.

Добавили контейнеры с сертификатами (каталог keys), Dockerfile и docker-compose.yml, дистрибутив csp (каталог csp), перешли на amd64 (на aarch64 ситуация аналогичная)

Теперь новый метод GetCert_6, который использует гост-сертификат из контейнера csp приводит к Stackoverflow. По http приложение работает, по https крашится. Что не так?

Как настраивали окружение:

  1. Как создавался контейнер (если делать с нуля, но сами контейнеры лежат в keys) /opt/cprocsp/bin/amd64/certmgr -install -pfx -file certificates/gost.pfx -pin 0123456789 -store uMy
  2. Добавить контейнер сертификатов в докер-контейнер (прописано в Dockerfile) /opt/cprocsp/bin/amd64/csptest -absorb -certs -provtype 80 -pattern "20c44e82"
  3. Проверить список установленных сертификатов (в т.ч. с приватными ключами) /opt/cprocsp/bin/amd64/certmgr -list

Как пользоваться: Запустить docker-compose для старта приложения docker-compose -f docker-compose.yml -p demo-kestrel up -d --build --force-recreate Остановить docker-compose docker-compose -f docker-compose.yml -p demo-kestrel down

Обновленный архив со всеми исходниками залил на облако, т.к. из-за дистрибутива csp не влазит по размеру во вложение.

@Fasjeit можете переоткрыть issue?

Fasjeit commented 1 year ago

@mevelop

Проблему с переполнением стека уже поправили в свежем релизе проблема - https://github.com/CryptoPro/libcore/issues/18 свежий релиз - https://github.com/CryptoPro/libcore/releases/tag/v2023.5.30.1

Попробуйте обновиться до него. Если ошибка на нём воспроизводится - сообщите.

mevelop commented 1 year ago

https://github.com/CryptoPro/libcore/releases/tag/v2023.5.30.1

Да, ошибка ушла. Но появилась другая (она же возникает на другом вашем проекте с 3.1 дотнетом):

2023-06-08 14:12:49 fail: Microsoft.AspNetCore.Server.Kestrel[0] 2023-06-08 14:12:49 Unhandled exception while processing 0HMR824VTBVAP. 2023-06-08 14:12:49 System.ComponentModel.Win32Exception (0x80090307): Unknown error -2146893049 2023-06-08 14:12:49 at System.Net.SSPIWrapper.AcquireCredentialsHandle(SSPIInterface secModule, String package, CredentialUse intent, SCHANNEL_CRED scc) 2023-06-08 14:12:49 at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(CredentialUse credUsage, SCHANNEL_CRED secureCredential) 2023-06-08 14:12:49 at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(X509Certificate certificate, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer) 2023-06-08 14:12:49 at System.Net.Security.CpSecureChannel.AcquireServerCredentials(Byte[]& thumbPrint, Byte[] clientHello) 2023-06-08 14:12:49 at System.Net.Security.CpSecureChannel.GenerateToken(Byte[] input, Int32 offset, Int32 count, Byte[]& output) 2023-06-08 14:12:49 at System.Net.Security.CpSecureChannel.NextMessage(Byte[] incoming, Int32 offset, Int32 count) 2023-06-08 14:12:49 at LibCore.Net.Security.CpSslStream.ProcessBlob(Int32 frameSize) 2023-06-08 14:12:49 at LibCore.Net.Security.CpSslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter) 2023-06-08 14:12:49 at LibCore.Net.Security.CpSslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm) 2023-06-08 14:12:49 at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context) 2023-06-08 14:12:49 at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.KestrelConnection`1.ExecuteAsync()

То есть http работает, а https по-прежнему нет

Fasjeit commented 1 year ago

В ближайшее время посмотрим проект вне докера.

Fasjeit commented 1 year ago

Добрый день.

Попробуйте воспроизвести ошибку, затем посмотреть syslog

tail -n 200 /var/log/syslog

Если в текстовках встречается "CryptoPro TLS. Server license not found. Since CSP5R2 you need an exclusive TLS Server license" значит не хватает серверной TLS лицензии для CSP (обычной серверной лицензии на CSP недостаточно)

Если же указанной ошибки нет - соберите пожалуйста отладочный лог.

Для этого перед запуском приложения выполните

cpconfig -loglevel ssp -mask 0x1f

для amd64 cpconfig должен находиться по пути /opt/cprocsp/sbin/amd64/.

После чего воспроизведите ошибку и приложите вывод syslog.

Лицензию для ознакомления можно попробовать получить написав на info@cryptopro.ru

Альтернативно можно попробовать использовать nginx для гостового TLS (есть форк от КриптоПро с поддержкой гостов). Т.е. в самом приложении (контейнере) не поднимать TSL силами Kerstrel, а иметь обычный http, который слушает локальный порт, а сам tls сделать через nginx с прокидыванием соединения на http порт. Сертификат клиента, в случае необходимости, также можно прокинуть в приложение через заголовок.

mevelop commented 1 year ago

В docker есть проблема с syslog, он не поддерживается нормально из коробки. Нашел логи контейнера, которые предполагаются должны быть заменой syslog, но там нет ваших логов, чисто дотнетовские. Еще старый тестовый сертификат истек, сделал новый. Но ошибки те же.

Лог docker-контейнера прикладываю docker_log.txt и новый сертификат с рутом gost_and_root.zip.

Пробовал использовать stunnel, но там та же самая ошибка возникает, с тем же кодом 0x80090307. Как будто что-то не то с сертификатом, но я же у вас в тестовом УЦ их беру. Вот тема на форуме, там так же все тестовое окружение с исходниками есть, может поможет.

Fasjeit commented 1 year ago

У вас введена лицензия на серверный TLS?

mevelop commented 1 year ago

Удалось добиться ответа от поддержки по почте практически через месяц. Они говорят, что в дистрибутив уже зашита 90-дневная лицензия (я подтверждаю это, так как клиентские запросы у меня работают). Какая тогда еще лицензия требуется для решения моего вопроса, чтобы принимать входящие TLS-запросы?

Ответ команды: /opt/cprocsp/sbin/aarch64/cpconfig -license -view

License validity: 5050N4003001**** Expires: 71 day(s) License type: Demo.

maxdm commented 1 year ago

Для серверного TLS необходима одна из этих лицензий: https://cryptopro.ru/order/OrderForm.aspx?catid=e8310f5f-a73f-eb11-80d9-0050569e915b

Лицензию для тестирования. как я понял, вам уже предоставила техподдержка.

Сценарий поддержки серверного TLS в .NET Core для нас не был приоритетным и сертифицированным регулятором этот вариант использования скорее всего не станет. В своих продуктах для организации TLS мы используем КриптоПро NGate или nginx. Чтобы расставить приоритеты хотелось бы получить подтверждение необходимости этих работ.

mevelop commented 1 year ago

Действительно, с Божьей помощью я добрался до сотрудника, кто понял меня и выдал мне тестовую серверную лицензию. Теперь лицензия выглядит так:

License validity: 505002301003*** Expires: 93 day(s) License type: TLS Server. Restrictions: 1000

С данным типом лицензии удалось принять запрос по https. Удивительно, что настолько сложно и неочевидно было:

  1. Догадаться до корня всех бед
  2. Получить тестовый ключ

По поводу сертификации мне неизвестно. Но ваш вариант поставки для классического .NET Framework, очевидно, уже отживает свое и будет только на старых проектах. Никаких новых продуктов там не предвидится, выбирать вам. Я свой выбор уже сделал :) Спасибо за помощь! Удачи в разработке)