Reputation: 10312
I'm currently working on an application running in Azure App Service that calls out to another service using WCF with TransportWithMessageCredential for the security and certificate-based authentication for the message credential. I'm able to retrieve a certificate from Azure Key Vault and use that certificate for my WCF ChannelFactory for the client for the service on my local development box just fine. However, as soon as I run the application on an Azure App Service vm, I get the following exception with all of my calls:
System.Security.Cryptography.CryptographicException: m_safeCertContext is an invalid handle.
at System.Runtime.AsyncResult.End (System.ServiceModel.Internals, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.ServiceModel.Channels.ServiceChannel+SendAsyncResult.End (System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.ServiceModel.Channels.ServiceChannel.EndCall (System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.ServiceModel.Channels.ServiceChannelProxy+TaskCreator+<>c__DisplayClass7_0`1.<CreateGenericTask>b__0 (System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at MyAzureAppServiceApp.Util.ServiceModelClient.ChannelFactoryExtensions+<UsingResultAsync>d__3`2.MoveNext (MyAzureAppServiceApp.Util.ServiceModelClient, Version=1.2.906.10, Culture=neutral, PublicKeyToken=null)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at MyAzureAppServiceApp.Data.WidgetRepository+<GetWidgetsByProjectAsync>d__5.MoveNext (MyAzureAppServiceApp.Data, Version=1.2.906.10, Culture=neutral, PublicKeyToken=null)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at MyAzureAppServiceApp.Service.Controllers.WidgetController+<GetWidgetsByProjectNumberAsync>d__6.MoveNext (MyAzureAppServiceApp.Service, Version=1.2.906.10, Culture=neutral, PublicKeyToken=null)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Threading.Tasks.TaskHelpersExtensions+<CastToObject>d__3`1.MoveNext (System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Web.Http.Controllers.ApiControllerActionInvoker+<InvokeActionAsyncCore>d__0.MoveNext (System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Web.Http.Controllers.ActionFilterResult+<ExecuteAsync>d__2.MoveNext (System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Web.Http.Filters.AuthorizationFilterAttribute+<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext (System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Web.Http.Filters.AuthorizationFilterAttribute+<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext (System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at System.Web.Http.Controllers.ExceptionFilterResult+<ExecuteAsync>d__0.MoveNext (System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35)
From what I've been able to ascertain so far, it looks like the by the time the X509Certificate2
is going to be used in a call by the ChannelFactory
, it's already been Dispose()
d. I've also already tried injecting fresh copies of the certificate into my ChannelFactory
s, and I still get the same error. Has anybody encountered anything like this trying to use WCF from an Azure App Service application ?
Upvotes: 1
Views: 1227
Reputation: 168
I was facing the same issue. For me the problem is that my code was something like:
using(var certificate = new X509Certificate2(privateKeyBytes, ...)
{
...
return certificate;
}
It seems that the certificate was being disposed before being returned. After removing the using
declaration it started to work.
Not sure if related to your scenario, but I think it's worth recording it somewhere :)
Upvotes: 0
Reputation: 10312
After struggling with this for several days, I was directed to this blog post by its author. Combining this with some improved exception handling and testing, I found out that you need to specify loading flags MachineKeySet | Exportable for the constructor of the X509Certificate2, otherwise the certificates won't load properly in an Azure App Service environment. This is due to the fact that Azure App Service VMs don't run local user profiles and as such don't have the user key store available to them. This ties to the constructor of X509Certificate2 and its defaults for how it stores private keys.
Upvotes: 2