Как вызвать веб-сервис с использованием клиентских сертификатов/взаимной аутентификации?

Я создаю клиент веб-службы, используя vb .net. Веб-сервис защищен ssl, базовой аутентификацией, а также требует клиентских сертификатов. Поэтому я создал веб-ссылку в Visual Studio и предоставил учетные данные:

Dim cred As New System.Net.NetworkCredential("usr", "passwd")
Dim proxy As New SimpleFromLocal.simple
proxy.Credentials = cred

Console.WriteLine(proxy.helloWorld())

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

Dim cert As X509Certificate = X509Certificate.CreateFromCertFile(certFile)
proxy.ClientCertificates.Add(cert)

Сертификат загружен, но вызов веб-службы завершается сбоем. Я мог бы опубликовать исключение, но оно на немецком языке, что само по себе является проблемой. В основном это говорит: Аутентификация не удалась, потому что удаленный сайт закрыл соединение. Я попытался отладить рукопожатие ssl на стороне сервера, и похоже, что сертификат клиента не передается.

Итак, что мне здесь не хватает? Обязательно ли устанавливать клиентский сертификат на локальную машину?

Редактировать: Возникла ошибка:

System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> 
System.IO.IOException: Authentication failed because the remote party has closed the transport stream. 
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.TlsStream.CallProcessAuthentication(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.ConnectStream.WriteHeaders(Boolean async)
--- End of inner exception stack trace ---
at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at CCClient.SimpleFromLocal.simple.helloWorld() in C:\TP\CCClient\CCClient\Web References\SimpleFromLocal\Reference.vb:Zeile 90.
at CCClient.Module1.clientWithProxy(NetworkCredential cred, String certFile)
in C:\TP\CCClient\CCClient\Module1.vb:Zeile 53.

person TPete    schedule 23.03.2012    source источник


Ответы (1)


Ну наконец то!

Этот вопрос заставил меня попробовать использовать X509Certificate2 (обратите внимание на 2 в имени класса). Я использовал его с хранилищем ключей PKCS#12, содержащим только один сертификат. Итак, вот что я сделал:

Создайте файл хранилища ключей

Для этого я использовал keytool Java. После создания самоподписанного сертификата его нужно было экспортировать в нужный формат:

keytool -importkeystore -srckeystore keystore.jks \
        -srcstoretype JKS \
        -destkeystore keystore.pfx \
        -deststoretype PKCS12

Примечание. Экспорт сертификата в файл и его непосредственное использование не работает.

Добавить сертификат клиента в прокси

Dim proxy As New SimpleFromLocal.simple
Dim cred As New NetworkCredential("usr", "passwd")
Dim cert As New X509Certificate2(certFile, "passwd")
proxy.Credentials = cred
proxy.ClientCertificates.Add(cert)

Console.WriteLine(proxy.helloWorld())

И это все. Та же установка не работает с использованием X509Certificate по каким-то причинам.

person TPete    schedule 26.03.2012
comment
В .NET иногда необходимо указать квитирование System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3; //используется SSL3, чтобы избежать проблем с рукопожатием - person Dasith Wijes; 26.09.2016