CryptoPro / libcore

44 stars 0 forks source link

TLS соединение через proxy #63

Closed Vanish-q closed 5 months ago

Vanish-q commented 5 months ago

Добрый день, у нас имеется сервер AstraLinux и приложение на C#. Приложению нужно установить соединение с сервером использующим TLS шифрование с ГОСТ сертификатами. Для установки соединения используется CpHttpHandler. При попытке установить соединение напрямую все работает корректно, но как только между нами и веб сервисом появляется прокси все перестает работать. Прокси пишет, что не понимает наш запрос, а мы в коде ловим ошибку в которой написано, что кадр поврежден

Ниже полная ошибка

One or more errors occurred. (Cannot determine the frame size or a corrupted frame was received. (172.19.196.113:3128))
System.AggregateException: One or more errors occurred. (Cannot determine the frame size or a corrupted frame was received. (172.19.196.113:3128))
 ---> System.Net.Http.HttpRequestException: Cannot determine the frame size or a corrupted frame was received. (172.19.196.113:3128)
 ---> System.IO.IOException: Cannot determine the frame size or a corrupted frame was received.
   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.<.ctor>b__3_0(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.AddHttp11ConnectionAsync(QueueItem queueItem)
   at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.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.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, 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)
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at TLSToSendError.Program.Main(String[] args) in C:\Work\000 Code\TLSToSendError\TLSToSendError\Program.cs:line 29

C:\Work\000 Code\TLSToSendError\TLSToSendError\bin\Debug\net8.0\TLSToSendError.exe (процесс 30408) завершил работу с кодом 0.

Версия ОС сервера - Astra Linux 1.7 c# Приложение использует .net8.0 В качестве прокси используется Squid

Запрос отправляется следующим образом

var cpHttpHandler = new CpHttpHandler()
{
    SslOptions = new CpSslClientAuthenticationOptions()
    {
        RemoteCertificateValidationCallback = CheckEGRZCertificate1,
    },

    UseProxy = true,
    Proxy = new System.Net.WebProxy("172.19.196.113", 3128),
};
var client = new HttpClient(cpHttpHandler);

string apiEndPoint = "https://lk.egrz.ru/assets/img/foto.jpg";
Uri uri = new Uri(apiEndPoint);

var responce = client.GetAsync(uri).Result;

var result = responce.Content.ReadAsStringAsync();

Функция CheckEGRZCertificate1 всегда возвращает true, но до ее вызова дело не доходит

Vanish-q commented 5 months ago

Отмечу, что ошибка полностью воспроизводится на ОС Ubuntu 22.04.4 LTS в WSL

maxdm commented 5 months ago

Предположу, что прокси как минимум должен поддерживать ГОСТ-TLS.

Vanish-q commented 5 months ago

Предположу, что прокси как минимум должен поддерживать ГОСТ-TLS.

Ранее при размещении приложения на windows сервере и использовании этого proxy все было в порядке. Так же с более ранними версиями либкоры, которые встраивались в стандартные библиотеки .net в рантайме все работало. Но уже сам сервер Astra Linux блокирует приложение из-за этого встраивания. Поэтому пришлось перейти на CpHttpClient.

yodasad commented 5 months ago

Добрый день!

Давайте начнём с tcpdump'a.

Vanish-q commented 5 months ago

Добрый день!

Давайте начнём с tcpdump'a.

tcpdump запускал следующей командой:

sudo tcpdump -i any -vv host 172.19.196.113 or lk.egrz.ru and port 3128 or 443

Вывод такой:

tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
13:08:19.753952 lo    In  IP (tos 0x0, ttl 64, id 44221, offset 0, flags [DF], proto TCP (6), length 60)
    172.19.196.113.53172 > 172.19.196.113.3128: Flags [S], cksum 0xe138 (incorrect -> 0x9796), seq 1855519323, win 65495, options [mss 65495,sackOK,TS val 1984830004 ecr 0,nop,wscale 7], length 0
13:08:19.753969 lo    In  IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    172.19.196.113.3128 > 172.19.196.113.53172: Flags [S.], cksum 0xe138 (incorrect -> 0x498f), seq 1001161171, ack 1855519324, win 65483, options [mss 65495,sackOK,TS val 1984830004 ecr 1984830004,nop,wscale 7], length 0
13:08:19.753975 lo    In  IP (tos 0x0, ttl 64, id 44222, offset 0, flags [DF], proto TCP (6), length 52)
    172.19.196.113.53172 > 172.19.196.113.3128: Flags [.], cksum 0xe130 (incorrect -> 0x704b), seq 1, ack 1, win 512, options [nop,nop,TS val 1984830004 ecr 1984830004], length 0
13:08:19.795491 lo    In  IP (tos 0x0, ttl 64, id 44223, offset 0, flags [DF], proto TCP (6), length 212)
    172.19.196.113.53172 > 172.19.196.113.3128: Flags [P.], cksum 0xe1d0 (incorrect -> 0xbf0b), seq 1:161, ack 1, win 512, options [nop,nop,TS val 1984830045 ecr 1984830004], length 160
13:08:19.795514 lo    In  IP (tos 0x0, ttl 64, id 13350, offset 0, flags [DF], proto TCP (6), length 52)
    172.19.196.113.3128 > 172.19.196.113.53172: Flags [.], cksum 0xe130 (incorrect -> 0x6f5a), seq 1, ack 161, win 511, options [nop,nop,TS val 1984830045 ecr 1984830045], length 0
13:08:19.797283 lo    In  IP (tos 0x0, ttl 64, id 13351, offset 0, flags [DF], proto TCP (6), length 3744)
    172.19.196.113.3128 > 172.19.196.113.53172: Flags [P.], cksum 0xef9c (incorrect -> 0x03a1), seq 1:3693, ack 161, win 512, options [nop,nop,TS val 1984830047 ecr 1984830045], length 3692
13:08:19.797298 lo    In  IP (tos 0x0, ttl 64, id 44224, offset 0, flags [DF], proto TCP (6), length 52)
    172.19.196.113.53172 > 172.19.196.113.3128: Flags [.], cksum 0xe130 (incorrect -> 0x60fc), seq 161, ack 3693, win 493, options [nop,nop,TS val 1984830047 ecr 1984830047], length 0
13:08:19.797694 lo    In  IP (tos 0x0, ttl 64, id 13352, offset 0, flags [DF], proto TCP (6), length 52)
    172.19.196.113.3128 > 172.19.196.113.53172: Flags [F.], cksum 0xe130 (incorrect -> 0x60e7), seq 3693, ack 161, win 512, options [nop,nop,TS val 1984830048 ecr 1984830047], length 0
13:08:19.799196 lo    In  IP (tos 0x0, ttl 64, id 44225, offset 0, flags [DF], proto TCP (6), length 52)
    172.19.196.113.53172 > 172.19.196.113.3128: Flags [F.], cksum 0xe130 (incorrect -> 0x60e4), seq 161, ack 3694, win 512, options [nop,nop,TS val 1984830049 ecr 1984830048], length 0
13:08:19.799262 lo    In  IP (tos 0x0, ttl 64, id 13353, offset 0, flags [DF], proto TCP (6), length 52)
    172.19.196.113.3128 > 172.19.196.113.53172: Flags [.], cksum 0xe130 (incorrect -> 0x60e3), seq 3694, ack 162, win 512, options [nop,nop,TS val 1984830049 ecr 1984830049], length 0

172.19.196.113 - ip WSL 3128 - порт на котором находится proxy lk.egrz.ru доменное имя сервиса, который используется ГОСТ TLS

yodasad commented 5 months ago

В файл сдампите всё

tcpdump -i <interface> -w <file>

и приложите файл к запросу, пожалуйста.

Vanish-q commented 5 months ago

Залил файл в облако, сюда приложить не давал https://disk.yandex.ru/d/WEUa2OfM1SuT1Q

yodasad commented 5 months ago

Весьма странный лог, TLS в нём нет. В лог попал вот такой ответ, видимо, от самого Squid:

<p><b>Unsupported Protocol</b></p>\n
<p>Squid does not support some access protocols. For example, the SSH protocol is currently not supported.</p>\n

Посмотрите лог самого прокси, возможно, это поможет решить проблему.

Поэкспериментируйте с различными конфигурациями:

Vanish-q commented 5 months ago

При использовании CpHttpHandler доступ к http://ya.ru через прокси устанавливается корректно, в логе самого прокси появляется следующие записи:

1718018577.004     25 172.19.196.113 TCP_MISS/301 1567 GET http://ya.ru/ - HIER_DIRECT/77.88.44.242 -
1718018577.215    177 172.19.196.113 TCP_TUNNEL/200 330918 CONNECT ya.ru:443 - HIER_DIRECT/77.88.44.242 -

Прокси судя по всему автоматом перекидывает на https

При попытке получить доступ к https://ya.ru на прокси ошибка 1718018094.882 1 172.19.196.113 NONE_NONE/400 3692 - error:invalid-request - HIER_NONE/- text/html такая же как и ранее возникала при подключении к lk.egrz.ru, а в коде абсолютно такая же ошибка как та что я указывал в самом начале обращения

Если же использовать HttpClientHandler то к ya.ru доступ дает как по http, так и по https.

Так же ранее пытался экспериментировать с настройками прокси, но пришел к выводу, что с ним ничего не сделать. Из-за того, что:

  1. На windows с тем же прокси работало корректно
  2. TLS соединение использующее не ГОСТ сертификаты не устанавливается
  3. Стандартный системный HttpClientHandler позволяет устанавливать соединение
  4. По документации проси не должен никак обрабатывать передаваемые пакеты, а только разрешать или запрещать доступ к определенным адресам

Дополнительно сделал отдельные файлы с логами tcpdump:

yodasad commented 5 months ago

Спасибо, посмотрим.

yodasad commented 5 months ago

Добрый день!

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

ВАЖНО! Исправление сделано только для .NET 8 (в .NET 6 данный сценарий поддерживаться не будет), соответственно, перед сборкой убедитесь, что ссылаетесь в проекте на версию фреймворка net8.0.

Vanish-q commented 5 months ago

Добрый день, проверил, заработало. Можете несколько сориентировать когда данные изменения появятся в релизной версии?

Fasjeit commented 5 months ago

Выпустили релиз под правку

https://github.com/CryptoPro/libcore/releases/tag/v2024.6.27