m_safeCertContext 是一个无效的句柄 - 为什么我的代码在生产环境中有效但在开发环境中无效?

m_safeCertContext is an invalid handle - why does my code work in production but not in dev environment?

在我的项目中启用 HTTPS 后,我开始收到错误页面:m_safeCertContext is an invalid handle

该代码在 Web 服务器上的生产环境中运行良好。

我是运行Visual Studio2017年15.3.0.

我已将 sslFlags 更新为 <access sslFlags="SslNegotiateCert" /> 并且我已确保设置了 iisClientCertificateMappingAuthentication 至 <iisClientCertificateMappingAuthentication enabled="true"></iisClientCertificateMappingAuthentication>

以下是我的 IIS Express 应用程序池设置:

<applicationPools>
            <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
            <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
            <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
            <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
            <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
            <applicationPoolDefaults managedRuntimeLoader="v4.0">
                <processModel loadUserProfile="true" />                                
            </applicationPoolDefaults>
</applicationPools>

错误页面的全文:

Server Error in '/' Application.
m_safeCertContext is an invalid handle.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Security.Cryptography.CryptographicException: m_safeCertContext is an invalid handle.

Source Error:


Line 383:                    HttpClientCertificate httpCert = HttpContext.Current.Request.ClientCertificate;
Line 384:                    X509Certificate2 x509Cert = new X509Certificate2(httpCert.Certificate);
Line 385:                    _subject = x509Cert.Subject;
Line 386:                    _sCustomerId = CustomerQueries.getCustomerId(_subject);
Line 387:                    LoadCustomerAttributes(CustomerQueries.getCustomerAttributes(_sCustomerId));

Source File: C:$TFS\Reports\Projects\WebMaster\Customers\Classes\Customer.cs    Line: 385

Stack Trace:


[CryptographicException: m_safeCertContext is an invalid handle.]
   System.Security.Cryptography.X509Certificates.X509Certificate.ThrowIfContextInvalid() +12505161
   System.Security.Cryptography.X509Certificates.X509Certificate.get_Subject() +14
   ReportsRG.Projects.WebMaster.Customers.Classes.Customer.GetUserDataFromCertificate() in C:$TFS\SMRT\Dev\ReportsRG\Projects\WebMaster\Customers\Classes\Customer.cs:385
   ReportsRG.Projects.WebMaster.Customers.Classes.Customer..ctor() in C:$TFS\SMRT\Dev\ReportsRG\Projects\WebMaster\Customers\Classes\Customer.cs:322
   MVCPages.Controllers.SmrtController.Index() in C:$TFS\SMRT\Dev\MVCPages\Controllers\SmrtController.cs:39
   lambda_method(Closure , ControllerBase , Object[] ) +61
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +14
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +157
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
   System.Web.Mvc.Async.<>c.<BeginInvokeSynchronousActionMethod>b__9_0(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +22
   System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +29
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +32
   System.Web.Mvc.Async.<>c__DisplayClass11_0.<InvokeActionMethodFilterAsynchronouslyRecursive>b__0() +58
   System.Web.Mvc.Async.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2() +228
   System.Web.Mvc.Async.<>c__DisplayClass7_0.<BeginInvokeActionMethodWithFilters>b__1(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +34
   System.Web.Mvc.Async.<>c__DisplayClass3_6.<BeginInvokeAction>b__4() +35
   System.Web.Mvc.Async.<>c__DisplayClass3_1.<BeginInvokeAction>b__1(IAsyncResult asyncResult) +100
   System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27
   System.Web.Mvc.<>c.<BeginExecuteCore>b__152_1(IAsyncResult asyncResult, ExecuteCoreState innerState) +11
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +29
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +45
   System.Web.Mvc.<>c.<BeginExecute>b__151_2(IAsyncResult asyncResult, Controller controller) +13
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +22
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +26
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
   System.Web.Mvc.<>c.<BeginProcessRequest>b__20_1(IAsyncResult asyncResult, ProcessRequestState innerState) +28
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +29
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +49
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +28
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9850009
   System.Web.<>c__DisplayClass285_0.<ExecuteStepImpl>b__0() +26
   System.Web.StepInvoker.Invoke(Action executionStep) +107
   System.Web.<>c__DisplayClass4_0.<Invoke>b__0() +23
   Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule.OnExecuteRequestStep(HttpContextBase context, Action step) +64
   System.Web.<>c__DisplayClass284_0.<OnExecuteRequestStep>b__0(Action nextStepAction) +56
   System.Web.StepInvoker.Invoke(Action executionStep) +91
   System.Web.<>c__DisplayClass4_0.<Invoke>b__0() +23
   Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule.OnExecuteRequestStep(HttpContextBase context, Action step) in /_/WEB/Src/Web/Web/ApplicationInsightsHttpModule.cs:164
   System.Web.<>c__DisplayClass284_0.<OnExecuteRequestStep>b__0(Action nextStepAction) +56
   System.Web.StepInvoker.Invoke(Action executionStep) +91
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +9956298
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +163

调用堆栈至少提供了足够的提示,说明下一步要查找什么。

Line 383:                    HttpClientCertificate httpCert = HttpContext.Current.Request.ClientCertificate;
Line 384:                    X509Certificate2 x509Cert = new X509Certificate2(httpCert.Certificate);
Line 385:                    _subject = x509Cert.Subject;

这段代码试图抓取浏览器发送的客户端证书,然后访问其Subject属性。此访问尝试失败并发生异常,

[CryptographicException: m_safeCertContext is an invalid handle.]
   System.Security.Cryptography.X509Certificates.X509Certificate.ThrowIfContextInvalid() +12505161
   System.Security.Cryptography.X509Certificates.X509Certificate.get_Subject() +14

由于 .NET Framework 通常包装本机 Windows API,因此异常本身可能会非常混乱。

“该代码在 Web 服务器上的生产环境中运行良好”,因此我可以假设您的服务器管理员已将此生产机器配置为知道如何为客户端证书构建完整链(非常常见的服务器配置),但是您在您的开发机器上可能没有做同样的事情。与服务器管理员交谈,了解您错过了什么。

在此期间,您可以在第384行设置一个中断并分析httpCert的更多细节。这可能会帮助您找出缺少的设置。

我更新了错误的 ApplicationHost.config 文件。

正确的位于解决方案根目录中的 .vs\config

我正在更新位于:C:\Users\[username]\Documents\IISExpress\config\

更新正确的 ApplicationHost.config 文件后,代码开始在我的本地开发环境中运行。