Ключевое слово в защите информации
ключевое слово
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Polooboy  
#1 Оставлено : 25 мая 2026 г. 13:29:49(UTC)
Polooboy

Статус: Новичок

Группы: Участники
Зарегистрирован: 08.04.2026(UTC)
Сообщений: 4
Российская Федерация

Подскажите, куда копать?

Взял код C# для .NET из примера:
https://dss.cryptopro.ru/libcore/docs/04-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/04-07-tls-get.html

Машина под Windows 10. КриптоПро установлен, с лицензиями: CSP 5.0.13600, TSP Client 2.0, OCSP Client 2.0
Проект на VS2022. В проект добавлены пакеты CryptoPro:
Цитата:
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CryptoPro.Net.Security" Version="2026.2.18" />
<PackageReference Include="CryptoPro.Security.Cryptography" Version="2026.2.18" />
<PackageReference Include="CryptoPro.Security.Cryptography.Pkcs" Version="2026.2.18" />
<PackageReference Include="CryptoPro.Security.Cryptography.Xml" Version="2026.2.18" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.v3" Version="3.2.2" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>

Контейнер ключа - в системном реестре. Непонятно только откуда будет браться пароль от контейнера. В любом случае его и не спрашивает и TLS не устанавливает.
Падает с ошибкой:
Цитата:
//Exception thrown: 'System.Net.Http.HttpRequestException' in System.Private.CoreLib.dll
//'GpbGate_xUnit.exe'(CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\9.0.16\System.IO.MemoryMappedFiles.dll'.Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
//System.Net.Http.HttpRequestException: Received an unexpected EOF or 0 bytes from the transport stream. (test.bank.ru:443)
// --->System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
// at CryptoPro.Net.Security.SslStreamEx.< FillHandshakeBufferAsync > g__InternalFillHandshakeBufferAsync | 189_0[TIOAdapter](TIOAdapter adap, ValueTask`1 task, Int32 minSize)
// at CryptoPro.Net.Security.SslStreamEx.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
// at CryptoPro.Net.Security.SslStreamEx.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
// at CryptoPro.Net.Http.CpHttpHandler.EstablishSslStreamAsync(CpSslClientAuthenticationOptions options, Stream innerStream, Uri originAuthority, CancellationToken cancellationToken)
// at CryptoPro.Net.Http.CpHttpHandler.ConnectAsync(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
// at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
// -- - End of inner exception stack trace-- -
// at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
// at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
// at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
// at System.Net.Http.HttpConnectionPool.InjectNewHttp11ConnectionAsync(QueueItem queueItem)
// at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
// at System.Net.Http.HttpConnectionWaiter`1.WaitForConnectionWithTelemetryAsync(HttpRequestMessage request, HttpConnectionPool pool, Boolean async, CancellationToken requestCancellationToken)
// at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
// at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
// at System.Net.Http.HttpClient.< SendAsync > g__Core | 83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
// at GpbGate_xUnit.UnitTest1.Twotls() in D: \Users\s.shirokov\Documents\ProjectsCode\Crypto\GpbGate_xUnit\UnitTest1.cs:line 328


Для проверки выполняю
Цитата:
csptest -tlsc -server test.bank.ru -user 43d767c8261ccdc8e811df1730c33a0786d071f8 -verbose
с тем же сертификатом. Выполняется успешно, выбрасывает окошко для ввода пароля контейнера, выполняет TLS рукопожатие и устанавливает соединение.
Цитата:
Protocol version: 3.3
ClientHello: RecordLayer: TLS, Len: 116
SessionId: (empty)
Cipher Suites: (c1 00) (c1 01) (c1 02) (ff 85) (00 81)
121 bytes of handshake data sent
1460 bytes of handshake data received
1126 bytes of handshake data received
2218 bytes of handshake data sent
31 bytes of handshake data received
Handshake was successful
SECPKG_ATTR_SESSION_INFO: Reuse: 0, SessionId: 6a14128c26b8bf21e0afe4339abf8c3c0643981cb64197a9e1a2f63955d182f9

SECPKG_ATTR_CIPHER_INFO: Version: 1
SECPKG_ATTR_CIPHER_INFO: Protocol: 303
SECPKG_ATTR_CIPHER_INFO: CipherSuite: ff85, TLS_GOSTR341112_256_WITH_28147_CNT_IMIT
SECPKG_ATTR_CIPHER_INFO: BaseCipherSuite: ff85
SECPKG_ATTR_CIPHER_INFO: Cipher: GOST 28147-89, Len: 256, BlockLen: 1
SECPKG_ATTR_CIPHER_INFO: Hash: GR 34.11-2012 256, Len: 256
SECPKG_ATTR_CIPHER_INFO: Exchange: GOST DH 34.10-2012 512, MinLen: 1024, MaxLen: 1024
SECPKG_ATTR_CIPHER_INFO: Certificate: GR 34.10-2012 512, KeyType: 26

SECPKG_ATTR_CONNECTION_INFO: Protocol: 0x800 (TLS 1.2)
SECPKG_ATTR_CONNECTION_INFO: Cipher: 0x661e (GOST 28147-89)
SECPKG_ATTR_CONNECTION_INFO: Cipher strength: 256
SECPKG_ATTR_CONNECTION_INFO: Hash: 0x8021 (GOST R 34.11-2012 (256))
SECPKG_ATTR_CONNECTION_INFO: Hash strength: 256
SECPKG_ATTR_CONNECTION_INFO: Exch: 0xaa43 (GOST R 34.10-2012 (512) Ephemeral)
SECPKG_ATTR_CONNECTION_INFO: Key exchange strength: 1024

SECPKG_ATTR_KEY_INFO: KeySize: 256
SECPKG_ATTR_KEY_INFO: SignatureAlgorithm: 0x2e3d, Name: GOST R 34.11 2012 512
SECPKG_ATTR_KEY_INFO: EncryptAlgorithm: 0x661e, Name: GOST 28147-89

SECPKG_ATTR_SUPPORTED_SIGNATURES: Supported signatures: (ee ee) (ef ef) (ed ed)




Offline Илья К.А.  
#2 Оставлено : 25 мая 2026 г. 14:31:30(UTC)
Илья К.А.

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 24.02.2026(UTC)
Сообщений: 21
Российская Федерация
Откуда: Москва

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 5 раз в 5 постах
Добрый день

Пароль можно передать в коде C# следующим образом:
Код:
var store = new CpX509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
using var cert = store.Certificates.Find(X509FindType.FindBySubjectName, "Test Certificate", false)[0];
string password = "12345678";
SecureString secureString = new SecureString();
foreach (char walk in password)
{
    secureString.AppendChar(walk);
}
Gost3410_2012_256CryptoServiceProvider privateKey = cert.PrivateKey as Gost3410_2012_256CryptoServiceProvider;
privateKey.SetContainerPassword(secureString);


Или установить сертификат в хранилище с сохранением пароля в контексте сертификата:
Код:
csptest.exe -ipsec -reg -mycert C:\путь\до\сертификата\certificate.cer -autocont -savepin -passw 12345678
Offline Polooboy  
#3 Оставлено : 25 мая 2026 г. 15:54:07(UTC)
Polooboy

Статус: Новичок

Группы: Участники
Зарегистрирован: 08.04.2026(UTC)
Сообщений: 4
Российская Федерация

Илья, добрый день. Благодарю за ответ.

Однако.
Добавил я в код пароль для контейнера. Результат не изменился.
Цитата:
System.Net.Http.HttpRequestException: Received an unexpected EOF or 0 bytes from the transport stream. (test.bank.ru:443)

Возможно упускаю что-то очевидное.
Пример в доке по libcore на вид - простейший. Он говорит о том, что для TLS соединения достаточно использовать фирменный
хэндлер CpHttpHandler и в SslOptions хэндлера подоткнуть объект CpX509Certificate2 с сертификатом клиента.
После этого берём HttpClient с данным хэндлером и делаем полезную работу на внешнем сервисе, а TLS будет пожимать нам руки, отдавать коннекшены и всё будет ОК.

Вопрос, почему этот код не работает?, если известно, что csptest -tlsc с тем же сертификатом на тот же внешний Url - работает!
(для публикации я изменил url внешнего сервиса)

Цитата:
[Fact]
public async Task Twotls()
{
string certPath = "e:\\Copy.cer";
//получим сертификат только с открытым ключом (ибо закрытый хранится в контейнере)
byte[] certBytes = File.ReadAllBytes(certPath);
CpX509Certificate2 cert = new CpX509Certificate2( certBytes, "", X509KeyStorageFlags.EphemeralKeySet);
Assert.False(cert.HasPrivateKey);

//параметры закрытого ключа получаем в утилите CpTools
string imageFQCN = "HDIMAGE\\\\oemkgkyg.000\\5A9F";
int providerType = 81;
string providerName = "Crypto-Pro GOST R 34.10-2012 Strong Cryptographic Service Provider";
string providerPassword = "1"; //пароль от контейнера

//работаем с контейнером
using (Gost3410_2012_512CryptoServiceProvider keyProvider = new Gost3410_2012_512CryptoServiceProvider(
new CpCspParameters(providerType, providerName, imageFQCN))) {

keyProvider.SetContainerPassword(RSAfabric.ToSecureString(providerPassword)); //пароль контейнера
//var privateKey = cert.PrivateKey; //так делать уже [deprecated], надо по-другому
var clientKeys = cert.CopyWithPrivateKey(keyProvider);
Assert.True(clientKeys.HasPrivateKey); //наш сертификат с закрытым и открытым ключом

//работаем с внешним сервисом
using (var httpClient = new HttpClient(new CpHttpHandler
{
SslOptions = new CpSslClientAuthenticationOptions()
{
ClientCertificates = [clientKeys],// Указываем сертификат TLS.
},
}))
{
try
{
//стучимся
var response = await httpClient.GetAsync("https://test.bank.ru", TestContext.Current.CancellationToken);
}
catch (Exception e)
{
//ошибка
Debug.WriteLine(e);
}
}
}
}
Offline Илья К.А.  
#4 Оставлено : 25 мая 2026 г. 16:13:25(UTC)
Илья К.А.

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 24.02.2026(UTC)
Сообщений: 21
Российская Федерация
Откуда: Москва

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 5 раз в 5 постах
Пример должен работать, проверял его с куском кода для передачи пароля.
По ошибке "Received an unexpected EOF or 0 bytes from the transport stream." - сервер неожиданно закрыл подключение.
Попробуйте установить соединение с нашим тестовым сервером https://tlsgost-256auth.cryptopro.ru/index.html
Нужно будет использовать сертификат с тестового УЦ: https://testgost2012.cryptopro.ru/certsrv/

Если с ним соединение проходит успешно, стоит посмотреть в сторону сервера. Можно собрать дамп трафика при помощи wireshark.
Используется ли на стороне test.bank.ru:443 IIS в качестве сервера?
Offline Polooboy  
#5 Оставлено : 26 мая 2026 г. 16:29:06(UTC)
Polooboy

Статус: Новичок

Группы: Участники
Зарегистрирован: 08.04.2026(UTC)
Сообщений: 4
Российская Федерация

Илья, добрый день.
Воспользовался Вашим советом, создал сертификат на тестовом УЦ. Спасибо КриптоПро! Сертификат, сервис, два клика и готово! Установил в системное хранилище Personal/CurrentUser.
Пробую фирменной утилитой csptest, всё хорошо.
Цитата:
csptest -tlsc -server tlsgost-256auth.cryptopro.ru -user dbb082a3c755ad93ab27385a0461ae47d6a70dc1
#0:
Subject: CN=Polooboy, OU=UIT, O=LDR, L=MSK, C=RU
Valid : 25.05.2026 13:08:40 - 03.07.2026 07:40:26 (UTC)
Issuer : OGRN=1234567890123, INN=001234567890, STREET=ул. Сущёвский вал д. 18, C=RU, S=г. Москва, L=Москва, O="ООО ""КРИПТО-ПРО""", CN="Тестовый УЦ ООО ""КРИПТО-ПРО"""

DContext expired: OK if file is completely downloaded
Reply status: HTTP/1.1 200 OK
1 connections, 640 bytes in 9.074 seconds;
Total: SYS: 0,250 sec USR: 0,125 sec UTC: 9,290 sec
[ErrorCode: 0x00000000]

Пробую из C#. Код не повторяю, без изменений. Стучусь на https://tlsgost-256auth.cryptopro.ru/index.html, использую тот же сертификат, что и в csptest.
Сообщение об ошибке немного другое. Смущает что якобы соединение было установлено, но сброшено на стороне "host machine". Что это может значить?
Далее, не может ничего прочесть в транспортном потоке, т.е.? он распарсить ответ не может?
Цитата:
System.Net.Http.HttpRequestException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.. (tlsgost-256auth.cryptopro.ru:443)
---> System.IO.IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine..
---> System.Net.Sockets.SocketException (10053): An established connection was aborted by the software in your host machine.
--- End of inner exception stack trace ---

Трассировка в WareShark, 193.37.157.97 - это tlsgost-256auth.cryptopro.ru
Цитата:
120 4.635476500 10.6.22.27 193.37.157.97 TCP 66 62038 → 443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM
121 4.639885800 193.37.157.97 10.6.22.27 TCP 66 443 → 62038 [SYN, ACK] Seq=0 Ack=1 Win=29200 Len=0 MSS=1400 SACK_PERM WS=128
122 4.640010400 10.6.22.27 193.37.157.97 TCP 54 62038 → 443 [ACK] Seq=1 Ack=1 Win=131584 Len=0
123 4.726947800 10.6.22.27 193.37.157.97 TLSv1 571 Client Hello (SNI=tlsgost-256auth.cryptopro.ru)
124 4.732635000 193.37.157.97 10.6.22.27 TCP 60 443 → 62038 [ACK] Seq=1 Ack=518 Win=30336 Len=0
125 4.733804900 193.37.157.97 10.6.22.27 TCP 1454 443 → 62038 [ACK] Seq=1 Ack=518 Win=30336 Len=1400 [TCP PDU reassembled in 128]
126 4.733808300 193.37.157.97 10.6.22.27 TCP 1454 443 → 62038 [ACK] Seq=1401 Ack=518 Win=30336 Len=1400 [TCP PDU reassembled in 128]
127 4.733883500 10.6.22.27 193.37.157.97 TCP 54 62038 → 443 [ACK] Seq=518 Ack=2801 Win=131584 Len=0
128 4.734092200 193.37.157.97 10.6.22.27 TLSv1 1266 Server Hello, Certificate, Certificate Request, Server Hello Done
129 4.734610900 10.6.22.27 193.37.157.97 TCP 54 62038 → 443 [FIN, ACK] Seq=518 Ack=4013 Win=130304 Len=0
130 4.738499300 193.37.157.97 10.6.22.27 TCP 60 443 → 62038 [RST, ACK] Seq=4013 Ack=519 Win=30336 Len=0
131 4.738626100 10.6.22.27 193.37.157.97 TCP 54 62038 → 443 [RST, ACK] Seq=518 Ack=4013 Win=0 Len=0
132 4.738683800 10.6.22.27 193.37.157.97 TCP 54 62038 → 443 [RST, ACK] Seq=519 Ack=4013 Win=0 Len=0
Понимаю, что скорее всего проблема локальная (где-то в жгутах проводов моего системника), но, может быть Вы встречались с таким?
Offline Илья К.А.  
#6 Оставлено : 26 мая 2026 г. 17:01:46(UTC)
Илья К.А.

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 24.02.2026(UTC)
Сообщений: 21
Российская Федерация
Откуда: Москва

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 5 раз в 5 постах
Попробую в ближайшее время ваш код у себя с той же версией libcore. С 2025.7.21 у меня ваш код запустился.
Судя по логу клиент (C#) закрыл соединение сразу после запроса сертификата сервером. Что странно, если других ошибок нет.

Можете попробовать пока тот код, что я использовал с загрузкой сертификата из хранилища:
Код:
var store = new CpX509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
using var cert = store.Certificates.Find(X509FindType.FindByThumbprint, "dbb082a3c755ad93ab27385a0461ae47d6a70dc1", false)[0];
string password = "1";
SecureString secureString = new SecureString();
foreach (char walk in password)
{
    secureString.AppendChar(walk);
}
Gost3410_2012_256CryptoServiceProvider privateKey = cert.PrivateKey as Gost3410_2012_256CryptoServiceProvider;
privateKey.SetContainerPassword(secureString);

using var httpClient =
    new HttpClient(
        new CpHttpHandler
        {
            SslOptions = new()
            {
                ClientCertificates = [cert],
                RemoteCertificateValidationCallback =
                    (object sender,
                        CpX509Certificate2? certificate,
                        CpX509Chain? chain,
                        SslPolicyErrors sslPolicyErrors) => true
            }
        });
Offline Polooboy  
#7 Оставлено : 27 мая 2026 г. 14:44:57(UTC)
Polooboy

Статус: Новичок

Группы: Участники
Зарегистрирован: 08.04.2026(UTC)
Сообщений: 4
Российская Федерация

Илья, спасибо Вам за помощь.

Я запустил ваш код на вашей версии libcore, результат тот же.
Скорее всего что-то не так исключительно на моём компе, это к libcore не имеет отношения.
Если можно, я напишу Вам в личку.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.