Я разрабатываю веб-приложение ASP.NET, которое отправляет запрос на другой сервер с помощью HttpWebRequest. Он отправляет запрос через HTTPS, а удаленному серверу требуется сертификат клиента. Запрос не работает в приложении .NET, видимо, не может отправить правильный сертификат клиента. Я могу успешно подключить и отправить сертификат клиента, если просто перейду к URL-адресу с помощью веб-браузера (специально для Chrome).
Нижеприведенный код представляет собой простое воспроизведение с простым базовым запросом GET.
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 4
- Недавно была установлена Microsoft.NET Framework 4.5. Еще не изучили, может ли это быть проблемой.
Вот все, что я пробовал, и то, что знаю:
- Этот код работал нормально при работе на компьютере под управлением Windows XP.
- Я гарантировал, что мой клиентский сертификат импортируется в хранилище локальных компьютеров, личных сертификатов, а разрешения Private Key правильно настроены для меня и всех соответствующих пользователей 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 и увидел это:
SecureChannel # 26717201 - У нас есть сертификаты, предоставленные пользователем. Сервер указал 6 эмитентов. Поиск сертификатов, соответствующих любому из эмитентов.
SecureChannel # 26717201 - Осталось 0 сертификатов клиентов на выбор.
...
InitializeSecurityContext (In-Buffers count = 2, Out-Buffer length = 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, чтобы сертификат выглядел как допустимый на моей машине. Это не устранило проблему.