Приложение .NET не может отправить сертификат клиента - Win 7 против Win XP? - PullRequest
17 голосов
/ 25 марта 2012

Я занимаюсь разработкой веб-приложения ASP.NET, которое отправляет запрос на другой сервер с помощью HttpWebRequest.Он отправляет запрос по HTTPS, а удаленному серверу требуется сертификат клиента.Сбой запроса в приложении .NET, по-видимому, не удается отправить правильный сертификат клиента.Я могу успешно подключиться и отправить сертификат клиента, если я просто захожу на URL через веб-браузер (в частности, в Chrome).

Приведенный ниже код является простым воспроизведением, с простойGET request.

var r = WebRequest.Create(url) as HttpWebRequest;
r.ClientCertificates = new X509CertificateCollection { myX509Cert };
using (var resp = r.GetResponse() as HttpWebResponse) {
    ...
}

Я получил наше любимое исключение: «Не удалось создать безопасный канал SSL / TLS».Как правило, эти типы проблем указывают на проблемы с разрешениями на закрытый ключ вашего сертификата.Я перепробовал все, что мог, чтобы убедиться, что все настроено правильно, но, возможно, я что-то упустил.Короче говоря, удаленный сервер отправляет TLS CertificateRequest со списком, который, похоже, правильно идентифицирует мой клиентский сертификат, но мое приложение не может ответить ни одним клиентским сертификатом.

Вот мои настройки:

  • 64-битная Windows 7 профессиональная
  • Возможность воспроизвести проблему в приложении ASP.NET MVC 3 / .NET 4, работающем на сервере разработки Visual Studio, ASP.NET WebForms /Приложение .NET 3.5, работающее как в локальном IIS, так и в консольном приложении .NET / .NET 4
  • Microsoft .NET Framework 4.5 было недавно установлено.Еще не изучили, может ли это быть проблемой

Вот все, что я пробовал, и то, что я знаю:

  • Этот код работал нормально при запускена компьютере с Windows XP
  • я гарантировал, что мой клиентский сертификат импортирован в локальный компьютер, хранилище личных сертификатов, с разрешениями личного ключа, правильно настроенными для меня и всех соответствующих пользователей IIS
  • Я попыталсяпереустановка сертификата на моей машине пару раз
  • Я подтвердил, что приложение .NET может получить доступ к сертификату X509 и HasPrivateKey = true
  • Гарантировал, что мой сертификат клиента действителен.На самом деле это сертификат SSL для веб-сервера, на котором будет работать это приложение
  • Я установил PreAuthenticate = true в объекте запроса.Не сделал различий
  • Я попытался установить ServicePointManager.Expect100Continue = false, не сделал различий
  • Я попытался установить ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3, но, очевидно, удаленный сервер требует TLS, такэто не помогает
  • Я установил ServicePointManager.ServerCertificateValidationCallback делегат, чтобы всегда возвращать true.Но запрос не выполняется ранее при подтверждении связи TLS, прежде чем он даже доходит до точки вызова этого делегата
  • Когда я перехожу по URL-адресу в Chrome, он запрашивает у меня сертификат клиента, представляет правильный сертификат клиентав качестве выбора я выбираю этот сертификат и получаю действительный ответ.Также работает правильно, когда я создаю запрос в Fiddler.Поэтому определенно возникает проблема с моим кодом .NET, а не с самим сертификатом или с удаленным сервером и т. Д.
  • Поставщик, с которым я работаю, настроил ту же службу на другом удаленном сервере.и эта служба требует другого сертификата клиента.Поэтому я попытался сделать то же самое с другим URL-адресом и сертификатом клиента и получил тот же сбой

Я добавил System.Net trace и увидел это:

SecureChannel # 26717201 - У нас есть предоставленные пользователем сертификаты.Сервер указал 6 эмитентов.Ищите сертификаты, которые соответствуют любому из эмитентов.

SecureChannel # 26717201 - осталось с 0 клиентскими сертификатами на выбор.

...

InitializeSecurityContext (количество в буферах= 2, длина Out-Buffer = 0, возвращенный код = CertUnknown).

Я включил полное протоколирование SCHANNEL и увидел это предупреждение:

Удаленный сервер запросил аутентификацию клиента SSL, но не удалось найти подходящий сертификат клиента. Будет предпринята попытка анонимного подключения. Этот запрос на соединение SSL может быть успешным или неуспешным, в зависимости от настроек политики сервера.

Я запустил Wireshark и увидел, что удаленный сервер отправил CertificateRequest, и, похоже, запись Distinguished Name имеет значения CN \ OU \ O моего клиентского сертификата, указанные точно. После этого мое приложение отправляет ответ сертификата без сертификатов.

Кажется, что я что-то упускаю при настройке этого сертификата для правильной работы с приложениями .NET в Windows 7. Я думаю, что на моем новом компьютере с Windows 7 что-то другое, по сравнению с компьютером с XP, то есть заставляя это потерпеть неудачу сейчас. У меня нет доступа к среде Windows XP, чтобы подтвердить это; Я через пару дней, но очень хотел бы разрешить это как можно скорее.

Любые идеи будут высоко оценены. Спасибо!

EDIT Как описано выше, при подключении к URL-адресу в Chrome браузер запрашивает у меня сертификат клиента, и я могу предоставить правильный сертификат и успешно подключиться. Однако я не могу сделать это успешно в Internet Explorer (9). Я просто получаю «Internet Explorer не может отобразить веб-страницу», без каких-либо других подсказок или объяснений. Мне сказали, что это может быть актуально, поскольку WebRequest.Create имеет поведение, подобное IE. Я изучаю, что это может означать, но оценил бы любые мысли по этому поводу.

EDIT Кроме того, я должен отметить, что удаленный сервер использует самозаверяющий сертификат SSL. Первоначально я думал, что это может быть проблемой, поэтому я добавил сертификат в качестве доверенного корня в MMC, чтобы сертификат был действительным на моем компьютере. Это не решило проблему.

Ответы [ 3 ]

8 голосов
/ 27 марта 2012

Это оказалось довольно простой проблемой, но ее было трудно определить.Удаленный сервер, на котором у моего приложения был клиентский сертификат в хранилище ключей, но нет корневых сертификатов в цепочке доверия сертификата моего клиента.

Я смог использовать свой код для успешной отправки запроса на другой серверчто требуется клиентские сертификаты.Я сделал захват в Wireshark при отправке этого успешного запроса, а также сделал захват при отправке неудачного запроса на другой сервер.В перехвате Wireshark я нашел «Server Hello» и сравнил сообщения, отправленные с удаленных серверов.«Хороший» удаленный сервер отправлял мой клиентский сертификат и также также свой корневой сертификат в разделе «Запрос сертификата» этого сообщения.«Плохой» удаленный сервер только отправлял мой клиентский сертификат.

Это напомнило мне, что диагностическая трассировка System.Net прочитала «Сервер указал 6 эмитентов ... Осталось выбрать 0 клиентских сертификатов»от".Таким образом, оказывается, что «эмитент» является ключевым термином здесь.Изначально это было просто упустить, потому что в моем первоначальном анализе рукопожатия TLS сервер отправлял мой клиентский сертификат в запросе сертификата.Оглядываясь назад, имеет смысл, что сервер должен отправлять ваш корневой сертификат, а не сам сертификат клиента.

7 голосов
/ 21 октября 2013

Я хотел бы добавить другое «решение» проблемы.

Сервер не может отправить правильный список эмитентов, если этот список слишком длинный.Кажется, это ограничение Microsoft.http://support.microsoft.com/kb/933430

Источник: http://netsekure.org/2011/04/tls-client-authentication-and-trusted-issuers-list/

Решение состоит в том, чтобы попросить сервер вообще не отправлять список.(Путем редактирования значения реестра)

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ SCHANNEL

Имя значения: SendTrustedIssuerList Тип значения: REG_DWORD Данные значения: 0 (Ложь)

0 голосов
/ 30 августа 2016

Для меня эти точные симптомы были вызваны использованием TLS 1.0, который не разрешал сервер. Это можно найти в журналах трассировки следующим образом:

Информация System.Net: 0: Аутентификация процесса (Протокол = Tls , Шифр = TripleDes 168 бит, Hash = Sha1 160 бит, ключ Обмен = RsaKeyX 2048 бит силы).

TLS 1.0 является значением по умолчанию для .NET 4.5, но его можно переопределить, установив:

ServicePointManager.SecurityProtocol = 
    SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...