Ядро DotNet: Как кроссплатформенной аутентификации клиента TLS сертификата? - PullRequest
1 голос
/ 09 мая 2019

Я пытаюсь разработать кроссплатформенное приложение (windows / mac os x), которое должно подписывать файлы XML и делать веб-запросы на сервере с использованием аутентификации ClientCertificate ...

Основное ограничениечто мне нужно использовать сертификат на смарт-карте ...

В настоящее время я использую ядро ​​dotnet 2.1.

Сначала я попытался использовать ядро ​​dotnet X509Store, но на MacOs яВ любом случае я не смог получить доступ к объекту PrivateKey (обязательно для подписи XML), затем я отбросил этот отрывПодписание XML (я обернул вызовы pkcs11interop внутри объекта RSA, затем я использовал этот объект как SigningKey внутри SignedXml,), но он не работал для соединения ClientCertificate.

Обычно я использую этот метод для подключения к серверу (dotnetFramework 4.6.1, только Windows):

HttpWebRequest req = WebRequest.Create("https://sometlsserver.com/") as HttpWebRequest;
req.ClientCertificates.Add(cert);
HttpWebResponse res = req.GetResponse() as HttpWebResponse;
using (StreamReader sr = new StreamReader(res.GetResponseStream(), new UTF8Encoding(false)))
{
    return sr.ReadToEnd();
}

И сертификат генерируется:

var certAttr = session.GetAttributeValue(handle, new List<CKA>
{
    CKA.CKA_VALUE,
};
var cert = new X509Certificate2(certAttr[0].GetValueAsByteArray());

Когда я пытаюсь установить соединение с моим классическимпоэтому у меня есть несколько исключений:

System.Net.WebException: The SSL connection could not be established, see inner exception. Authentication failed, see inner exception.
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception: Le message reçu était inattendu ou formaté de façon incorrecte
   --- End of inner exception stack trace ---
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   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.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslState.ThrowIfExceptional()
   at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__47_1(IAsyncResult iar)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at System.Net.HttpWebRequest.SendRequest()
   at System.Net.HttpWebRequest.GetResponse()
   --- End of inner exception stack trace ---
   at System.Net.HttpWebRequest.GetResponse()
...

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

Я пыталсячтобы добавить мой объект RSA, используемый для подписи XML, в свойстве закрытого ключа, но с ядром dotnet оно заканчивается PlatformNotSupportedException ...

cert.PrivateKey = myRSAObject; // simple

Мне интересно, возможно ли это сделать без использования стороннего поставщика?библиотека ...

Примечание. Перевод французского сообщения об ошибке «Сообщение было неожиданно или неправильно отформатировано.»

Спасибо.

(редактирование: лучшее форматирование)

1 Ответ

0 голосов
/ 09 мая 2019

X509Certificate2 - это унаследованный класс, разработанный только для Windows, который в настоящее время не имеет широко используемой альтернативы или разумной многоплатформенной замены.

Когда вы создаете X509Certificate2 объект, используя byte[] значение атрибута CKA_VALUE, вы получаете только сертификат без закрытого ключа.

Самое близкое к ".NET-совместимой реализации" вы можете реализовать класс, полученный из RSA, как я это делал в Pkcs11Interop.X509Store проекте. Он будет работать с классом SignedXML, но, как вы уже выяснили, его нельзя будет использовать с большинством классов SSL, для которых требуется объект X509Certificate2 с правильно связанным свойством PrivateKey.

ИМО у вас есть три варианта:

  1. Переключитесь на соответствующую версию .NET Core и создайте объект X509Certificate2, связанный с вашей реализацией RSA, используя CopyWithPrivateKey метод расширения , как указано @FilipNavara в его комментарии. Такой X509Certificate2 объект может (или скорее не может) работать с реализацией SSL.

  2. Используйте файл PFX / PKCS # 12, который содержит сертификат клиента SSL с закрытым ключом, защищенным паролем пользователя. Такой файл можно загрузить в X509Certificate2 объект, правильно связанный со свойством PrivateKey на большинстве платформ, поддерживаемых .NET Core.

  3. Поиск или запись реализации клиента SSL, для которой не требуется объект X509Certificate2 со связанным свойством PrivateKey. В настоящее время я не знаю ни одной библиотеки с таким дизайном.

...