ASP.NET Core Kestrel в Linux никогда не запрашивает сертификат клиента

У меня есть приложение ASP.NET Core 1.1, настроенное на использование Https и требующее сертификаты клиента:

Основной код приложения

Я запускаю приложение на Linux.

Если я изменю ClientCertificateMode на "AllowCertificates", то все работает нормально, но браузер никогда не запрашивает сертификат клиента.

С установленным "RequireCertificate" браузер по-прежнему не запрашивает сертификат, и я получаю два нижеприведенных исключения (оба повторяются четыре раза) на стороне сервера, и ответ не возвращается браузеру:

Microsoft.AspNetCore.Server.Kestrel: Ошибка: ConnectionFilter.OnConnection

System.AggregateException: произошла одна или несколько ошибок. (Аутентификация не удалась, потому что удаленная сторона закрыла транспортный поток.) ​​---> System.IO.IOException: Аутентификация не удалась, потому что удаленная сторона закрыла транспортный поток. в System.Net.Security.SslState.StartReadFrame(буфер Byte[], int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest) - место, где ранее находилось исключение, из которого была получена конечная точка --- в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult) в System.Net.Security.SslState.EndProcessAutheurity (IAs). SslStream.EndAuthenticateAsServer (IAsyncResult asyncResult) в System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 обещание, Boolean требуется синхронизация) --- Конец трассировки стека из предыдущего местоположения, в котором было сгенерировано исключение --- в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(задача задачи) в Microsoft.AspNetCore.Server.Kestrel.Https.HttpsConnectionFilter.d__3.MoveNext() --- Конец внутренней трассировки стека исключений --- ---> (Внутреннее исключение #0) System.IO.IOException: Ошибка аутентификации из-за удаленного Партия закрыла транспортный поток. в System.Net.Security.SslState.StartReadFrame(буфер Byte[], int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest) - место, где ранее находилось исключение, из которого была получена конечная точка --- в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult) в System.Net.Security.SslState.EndProcessAutheurity (IAs). SslStream.EndAuthenticateAsServer (IAsyncResult asyncResult) в System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 обещание, Boolean требуется синхронизация) --- Конец трассировки стека из предыдущего местоположения, в котором было сгенерировано исключение --- в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(задача задачи) в Microsoft.AspNetCore.Server.Kestrel.Https.HttpsConnectionFilter.d__3.MoveNext ()<---

Microsoft.AspNetCore.Server.Kestrel: Ошибка: ConnectionFilter.OnConnection

System.AggregateException: произошла одна или несколько ошибок. (Удаленный сертификат является недействительным в соответствии с процедурой проверки.) ---> System.Security.Authentication.AuthenticationException: Удаленный сертификат является недействительным в соответствии с процедурой проверки. в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Net.Security.SslState.StartSendAuthResetSignal(сообщение ProtocolToken, исключение AsyncProtocolRequest asyncRequest, исключение ExceptionDispatchInfo) в качестве сообщения System.Net.Request System.Net.Security.SslState.StartSendBlob(Byte[] входящий, Int32 count, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessReceivedBlob(байт [], Int32 count, AsyncProtocolRequest asyncReecest.Security.Request). SslState.StartReadFrame (буфер Byte[], int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.StartReceiveBlob (буфер Byte[], AsyncProtocolRequest asyncRequest) в качестве объекта.) в System.Net.Security.SslState.StartSendBlob (Byte[] входящий, число Int32, AsyncProtocolRequest asyn cRequest) в System.Net.Security.SslState.ProcessReceivedBlob(буфер Byte[], число Int32, AsyncProtocolRequest asyncRequest) в буфере System.Net.Security.SslState.StartReadFrame(Byte[], readBytes Int32 asestyn.Request)..Security.SslState.StartReceiveBlob (буфер Byte[], AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.CheckCompletionBeforeNextReceive (сообщение ProtocolToken, AsyncProtocolRequest asyncRequest) [, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessReceivedBlob(буфер Byte[], счетчик Int32, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.StartReadFrame(системный буфер Byte[], AsynRequest).Net.Security.SslState.StartReceiveBlob (буфер Byte[], AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.CheckCompletionBeforeNextReceive (сообщение ProtocolToken, AsyncProtoco lRequest asyncRequest) в System.Net.Security.SslState.StartSendBlob (Byte[] входящий, счетчик Int32, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessReceivedBlob(байт [], запрос системного запроса).NET.Security.SslState.StartReadFrame (буфер Byte[], int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest) --- исключение конца стека из предыдущего расположения в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult) в System.Net.Security.SslState.EndProcessAuthetification ((IAsyncResult asyncResult) в System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 обещание, Boolean требуется синхронизация) --- Конец трассировки стека из предыдущего местоположения, в котором было сгенерировано исключение --- в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(задача задачи) в Microsoft.AspNetCore.Server.Kestrel.Https.HttpsConnectionFilter.d__3.MoveNext() --- Конец внутренней трассировки стека исключений --- ---> (Внутреннее исключение #0) System.Security.Authentication.AuthenticationException: Удаленный сертификат является недействительным в соответствии с процедурой проверки. в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Net.Security.SslState.StartSendAuthResetSignal(сообщение ProtocolToken, исключение AsyncProtocolRequest asyncRequest, исключение ExceptionDispatchInfo) в качестве сообщения System.Net.Request System.Net.Security.SslState.StartSendBlob(Byte[] входящий, Int32 count, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessReceivedBlob(байт [], Int32 count, AsyncProtocolRequest asyncReecest.Security.Request). SslState.StartReadFrame (буфер Byte[], int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.StartReceiveBlob (буфер Byte[], AsyncProtocolRequest asyncRequest) в качестве объекта.) в System.Net.Security.SslState.StartSendBlob (Byte[] входящий, число Int32, AsyncProtocolRequest asyn cRequest) в System.Net.Security.SslState.ProcessReceivedBlob(буфер Byte[], число Int32, AsyncProtocolRequest asyncRequest) в буфере System.Net.Security.SslState.StartReadFrame(Byte[], readBytes Int32 asestyn.Request)..Security.SslState.StartReceiveBlob (буфер Byte[], AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.CheckCompletionBeforeNextReceive (сообщение ProtocolToken, AsyncProtocolRequest asyncRequest) [, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessReceivedBlob(буфер Byte[], счетчик Int32, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.StartReadFrame(системный буфер Byte[], AsynRequest).Net.Security.SslState.StartReceiveBlob (буфер Byte[], AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.CheckCompletionBeforeNextReceive (сообщение ProtocolToken, AsyncProtoco lRequest asyncRequest) в System.Net.Security.SslState.StartSendBlob (Byte[] входящий, счетчик Int32, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessReceivedBlob(байт [], запрос системного запроса).NET.Security.SslState.StartReadFrame (буфер Byte[], int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest) --- исключение конца стека из предыдущего расположения в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult) в System.Net.Security.SslState.EndProcessAuthetification ((IAsyncResult asyncResult) в System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 обещание, Boolean требуется синхронизация) --- Конец трассировки стека из предыдущего местоположения, в котором было сгенерировано исключение --- в System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(задача задачи) в Microsoft.AspNetCore.Server.Kestrel.Https.HttpsConnectionFilter.d__3.MoveNext ()<---

Скриншот браузера

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

2 ответа

Не уверен, что вы нашли решение этой проблемы, но недавно я столкнулся с подобной проблемой. Я обнаружил, что если у вас нет клиентских сертификатов, подписанных центром сертификации, которому доверяет сервер, вам не будет предложено. Мое решение состояло в том, чтобы добавить корневой ЦС в хранилище доверенных сертификатов в Linux, и после этого сертификат клиента будет отправлен / запрошен соответствующим образом.

В итоге я использовал IIS в качестве обратного прокси-сервера, чтобы получить информацию о сертификате (и выполнить проверку), а затем передать ее в заголовках в Kestrel.

Другие вопросы по тегам