Ошибки при подключении клиента TLS 1.0 к моей службе ASP .Net Core - PullRequest
0 голосов
/ 06 июня 2019

TL; DR: как настроить службу ASP.Net Core, которая:

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

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

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

Сертификат генерируется через оболочку вокруг dll 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 не понимает.

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

Спасибо.

1 Ответ

0 голосов
/ 15 июня 2019

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

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

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

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

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

Последняя часть, похоже, была настоящим ключом к этому. Когда сертификат имел расширение «Key Usage», помеченное как критический , оно просто не работало.

Что было очень странным, так это то, что, даже глядя на сетевой трафик, вы никогда не видели, чтобы сервер действительно отправлял сертификат клиенту (обычно все, что вы видите, это клиент, отправляющий 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 довольны.

...