Не удается подключиться к серверу SSL, который использует только эфемерные наборы шифров (невозможно связаться с местным органом безопасности)

Я пытаюсь подключиться к тестовому серверу, запущенному с помощью openssl (предназначена эта ограниченная комбинация шифров):

openssl s_server -accept 443 -www -tls1_2 -cipher ECDHE:DHE:EDH -cert selfsignedcert.pem -key sskey.pem

Код, который я использую, похож на код msdn.

public static bool ValidateServerCertificate(
      object sender,
      X509Certificate certificate,
      X509Chain chain,
      SslPolicyErrors sslPolicyErrors)
{
        return true;
}

...

var client = new TcpClient(target, port);
SslStream sslStream = new SslStream(client.GetStream(), false,ValidateServerCertificate,null);
sslStream.AuthenticateAsClient(target, null, SslProtocols.Tls12, false);

Но я получаю исключение в последней строке: A call to SSPI failed, see inner exception., где внутреннее исключение говорит: The Local Security Authority cannot be contacted. Глядя на wireshark, я могу сказать, что рукопожатие TLS заканчивается на Server Hello, Certificate, Server Key Exchange, Server Hello Done, а выбранный набор шифров — TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f).

Я могу получить доступ к URL-адресу с помощью Firefox, но не с IE (он просто говорит «Эта страница не может быть отображена»), поэтому это похоже на проблему с каналом.

Все работает нормально (IE и код), когда я запускаю сервер со всеми наборами шифров (-cipher ALL). Есть ли способ заставить его работать без изменения конфигурации сервера?

Stacktrace на всякий случай

    at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)

Я использую Windows 8.1 с последними обновлениями.


person savageBum    schedule 27.05.2015    source источник
comment
Попробуйте указать свой собственный параметр DH с разрядностью не менее 1024 бит. По умолчанию для s_server используются слабые 512 бит, которые могут быть неприемлемы для IE.   -  person Steffen Ullrich    schedule 27.05.2015
comment
@SteffenUllrich спасибо, использование пользовательских 1024-битных параметров помогло. Но мой вопрос заключается в том, как подключиться к этому серверу без изменения его конфигурации, т.е. как обойти эту защиту в schannel   -  person savageBum    schedule 27.05.2015
comment
Я не думаю, что стоит обходить эту проверку, см. weakdh.org. И ожидайте, что другие браузеры и библиотеки тоже получат это ограничение. Форки OpenSSL BoringSSL и LibreSSL уже некоторое время имеют ограничение в 1024 бита, и нет возможности его обойти. Но вы можете использовать более новую версию OpenSSL (после 1.02), где они больше не используют 512-битный DH по умолчанию в s_server.   -  person Steffen Ullrich    schedule 27.05.2015
comment
Я знаю об этом. Дело в том, что я использую свою программу для проверки конфигурации SSL/TLS удаленных серверов (плохие сертификаты, слабые наборы шифров и т. д.), поэтому она мне нужна для подключения даже к небезопасным службам. Пока похоже, что schannel не для этой работы.   -  person savageBum    schedule 27.05.2015


Ответы (1)


Мне удалось установить минимальную длину ключа для schannel с помощью реестра Windows.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman]
"ClientMinKeyBitLength"=dword:00000200

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

person savageBum    schedule 27.05.2015
comment
Вроде, как бы, что-то вроде. Вместо использования schannel я использовал openssl, управляемую оболочку, если быть точным openssl-net. - person savageBum; 10.03.2017