Ошибки при подключении клиента TLS 1.0 к моей службе ASP .Net Core

Вкратце: как настроить службу ASP.Net Core, которая:

  • Установлен в Windows (7 и выше, хотя я разрабатываю/тестирую на Windows 10)
  • Подает данные через HTTPS
  • Использует самозаверяющий SSL-сертификат (клиенты будут находиться в той же локальной сети, что и служба, и будут доступны через локальное имя хоста, поэтому покупка сертификата нецелесообразна)
  • Разрешает подключаться клиентам TLS1.0 (к сожалению, работает в Windows XP)

У меня нет проблем с первыми тремя вещами, у меня проблемы только с клиентами TLS 1.0.

Я не верю, что это проблема с моей службой, а скорее с ОС Windows и/или самозаверяющим сертификатом SSL.

Сертификат создается через оболочку библиотеки CERTENROLLLib. Я могу изменить способ его генерации (длину ключа, алгоритмы хеширования и т. д.), но это (очевидно) не моя область знаний....

Несколько клиентов на базе Windows 7 и более поздних версий работают нормально, при условии, что у них есть самозаверяющий сертификат, добавленный в качестве доверенного сертификата, и/или они просто написаны так, чтобы не отклонять этот сертификат...

Когда клиенты (ну, единственный клиент, который у меня есть для тестирования), поддерживающий только TLS 1.0, пытаются подключиться, они получают ошибки SSL, и я вижу в своих журналах системных событий Windows 10 следующее:

An TLS 1.0 connection request was received from a remote client application, 
but none of the cipher suites supported by the client application are 
supported by the server. The TLS connection request has failed.

Если я создам локальный клиент на своем компьютере и заставлю его использовать только TLS 1.0 через:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

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

Я следовал различным советам, найденным в Интернете, о том, чтобы моя установка Windows 10 принимала подключения TLS 1.0, и считаю, что она настроена для этого.

Поэтому я думаю, что проблема заключается в следующем:

  • Моя машина с Windows будет принимать соединения TLS1.0, но не имеет какой-либо формы шифрования, которую запрашивает клиент Windows XP, поэтому они не могут договориться; или же
  • Самозаверяющий сертификат использует алгоритм хеширования, который клиент Windows XP не понимает.

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

Спасибо.


person GPW    schedule 06.06.2019    source источник
comment
TLS 1.0 на самом деле не лучше, чем вообще отсутствие SSL. На самом деле это не то, что вы должны искать для включения. Клиентам, которые не поддерживают по крайней мере TLS 1.1, необходимо выполнить обновление. Windows 7 в любом случае будет мертва к следующему году, а XP мертва уже некоторое время.   -  person Chris Pratt    schedule 06.06.2019
comment
Я согласен. Однако клиенты представляют собой сделанные на заказ аппаратные терминалы, которые мы не можем изменить... И отсутствие поддержки ставит нас в невыгодное положение. Мое полусерьезное предложение состояло в том, чтобы на самом деле просто использовать http для этих терминалов, и если кто-то укажет на отсутствие безопасности, просто укажите, что tls 1.0 в любом случае так же плох, как и ничего. Надеюсь, чтобы заставить производителей обновиться.   -  person GPW    schedule 06.06.2019
comment
Проблема в том, что XP не может согласовывать какие-либо наборы шифров на основе AES (он этот старый), и, как вы определили, пересечение между поддерживаемыми наборами шифров очень мало. Также не гарантируется, что будет использоваться верхнее пересечение, поскольку оно должно учитывать несколько аспектов рукопожатия. Также учитывается, как вы вызываете API.   -  person Steve    schedule 10.06.2019


Ответы (1)


Актуальная проблема

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

У нас был доступ к стороннему сервису, который был доступен с компьютера XP через SSL. В этой системе было несколько отличий (размещенных на Win7/IIS по сравнению с win10/Kestrel, но после их устранения (путем размещения базового сайта на IIS/win 7 с использованием разных сертификатов) я в конце концов обнаружил, что это был просто сертификат.

Тщательный анализ одного рабочего сертификата и самоподписанных сертификатов, которые мы генерировали, выявил ряд отличий:

  • SHA-1 по сравнению с другим, более надежным шифрованием
  • очень ограниченная другая информация (например, субъект/эмитент был просто именем хоста, никаких дополнительных материалов DNS и т. д.
  • Часть «Использование ключа» была помечена как критическая на наших самозаверяющих сертификатах, но нет на рабочем сертификате

Последняя часть, кажется, была настоящим ключом к этому. Если сертификат имел расширение «Использование ключа», помеченное как критическое, он просто не работал.

Что было очень странно, так это то, что даже при просмотре сетевого трафика вы никогда не видели, как сервер фактически отправляет сертификат обратно клиенту (обычно все, что вы видите, это то, что клиент отправляет пакеты ClientHello TLS), поэтому я не совсем понимаю как это вызвало проблему, но это определенно был сертификат.

Исправление:

Первоначально мы использовали код C#, который был обернут вокруг библиотеки взаимодействия CERTENROLLLib для создания сертификатов. Оказывается, где-то в этом коде есть ошибка, а это означает, что даже если эти части были явно определены как Critical=false;, они все равно в конечном итоге будут помечены как Критические :

var keyUsageClass = new CX509ExtensionKeyUsageClass();
keyUsageClass.InitializeEncode(
      CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE
      | CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE
      | CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
                );
//This appears to be IGNORED;  maybe fixed in some later version, no idea.
keyUsageClass.Critical = false;

...

cert.InitializeFromPrivateKey(
  X509CertificateEnrollmentContext.ContextMachine, 
  privateKey, "");

cert.X509Extensions.Add((CX509Extension)keyUsageClass);

В конце концов я просто использовал powershell. Похоже, проблема все еще существует, но с New-SelfSignedCertificate cmdLet по крайней мере возможно указать использование ключа None (кажется невозможным через CertEnrollLib), что означает, что этот раздел полностью опущен.

Для справки, это раздел сценария powershell, который я использовал, который создает сертификат, а затем сохраняет его в файле .pfx для импорта на клиентах как «доверенный».

#various vars to use in the create command
$certSubject = $env:computername
$certFriendlyName= "$($certSubject)_MyCert"
$certPfxFileName = "$($certFriendlyName).pfx"
$expiryDate = (Get-Date).AddYears(10)
$flagsForServerCert = "2.5.29.37={text}1.3.6.1.5.5.7.3.1"
$certPassword = "somePassword123!"

#Note: this is one command, on one line, broken here for readability:
New-SelfSignedCertificate 
  -DNSName $certSubject 
  -FriendlyName $certFriendlyName 
  -certstorelocation cert:\localmachine\my 
  -subject $certSubject 
  -HashAlgorithm SHA 
  -NotAfter $expiryDate 
  -TextExtension $flagsForServerCert 
  -KeyUsage None

#Now we need to fetch the thumbprint of that cert.  note, multiple matching Certs will 
#mean this doesn't work, so ensure FriendlyName is unique in the first place.
$thumbprint=(Get-ChildItem -Path cert:\localmachine\my | Where-Object {$_.FriendlyName -match $certFriendlyName}).Thumbprint

#Now to save as a pfx file, need to create a SecureString from the password.
$pwd = ConvertTo-SecureString -String $certPassword -Force -AsPlainText 

#Get the certificate, and pipe it through Export-PfxCertificate to save it.
Get-ChildItem -Path "cert:\localmachine\my\$($thumbprint)" | Export-PfxCertificate -FilePath $certPfxFileName -Password $pwd 

Затем был сгенерирован сертификат сервера, которым довольны клиенты XP.

person GPW    schedule 15.06.2019