Unable to consume SOAP service, with Client Certificate, in ASP.NET Core 2.1

0

I'm attempting to port from 4.6.1 to ASP.NET Core 2.1.0-preview1. The following code throws an exception "Could not establish trust relationship for the SSL/TLS secure channel with authority '[service url]:447'

Am I applying the client cert incorrectly?

X509Certificate cert = X509Certificate2.CreateFromCertFile("C:\\mycert.cer");
X509Certificate2 cert2 = new X509Certificate2(cert);


var binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var endpoint = new EndpointAddress(new Uri("https://[service url]"));
var channelFactory = new ChannelFactory<APIWebService>(binding, endpoint);
channelFactory.Credentials.ClientCertificate.Certificate = cert2;
var serviceClient = channelFactory.CreateChannel();
var result = serviceClient.getBatchesSinceGUID(new getBatchesSinceGUIDRequest("-1"));
channelFactory.Close();

FACTS

  1. The X509Certificate is known to work with the 4.6.1 code; Allthough, the CORE version is using X509Certificate2
  2. In the 4.6.1 version, the APIWebService proxy was generated with wsdl.exe
  3. In the ASP.NET Core version, the APIWebService proxy was generated with svcutil.exe

EXCEPTION STACKTRACE

System.ServiceModel.Security.SecurityNegotiationException
  HResult=0x80131500
  Message=Could not establish trust relationship for the SSL/TLS secure channel with authority '[server url]:447'.
  Source=System.Private.ServiceModel
  StackTrace:
   at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(HttpRequestException requestException, HttpRequestMessage request, HttpAbortReason abortReason)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpClientRequestChannel.HttpClientChannelAsyncRequest.<SendRequestAsync>d__13.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.ServiceModel.Channels.RequestChannel.<RequestAsync>d__33.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.ServiceModel.Channels.RequestChannel.<RequestAsyncInternal>d__32.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.TaskHelpers.WaitForCompletionNoSpin[TResult](Task`1 task)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(MethodCall methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(MethodInfo targetMethod, Object[] args)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)
   at generatedProxy_1.getDispatchBatchesSinceUID(getDispatchBatchesSinceUIDRequest )
   at NCPA.NADS.Test.UnitTest1.AdsDownload_Test() in UnitTest1.cs:line 26

Inner Exception 1:
HttpRequestException: An error occurred while sending the request.

Inner Exception 2:
WinHttpException: A security error occurred
ssl
soap
asp.net-core
asked on Stack Overflow Apr 18, 2018 by John McCann • edited Apr 18, 2018 by John McCann

1 Answer

1

Looks like it's probably because it's not being provided with its private key. When doing mutual certificate authentication, both parties need their public/private key pairs to establish a secure and properly authenticated channel.

In general, a .cer file typically contains only the certificate itself, which is the public key plus some metadata and the CA signature. The private key is held either in the certificate store (if it was generated/installed locally) or in a .pfx file (which will generally be either password-protected or permission-restricted).

If you do it with a .pfx file, rather than loading from the local cert store, be VERY sure that you do the following:

  • Restrict permissions on the file to read-only for the account under which the application runs and read/write for ONLY administrators/developers who can be trusted with the private key.
  • If it is a password-protected file, DO NOT hard code the password in your code or check it in to source control. That completely defeats the purpose and you might as well not do HTTPS. Anyone who can check out your code and key file could authenticate as that account.
  • Same comment for the .pfx file itself - don't put it in source control.
answered on Stack Overflow Apr 18, 2018 by dodexahedron

User contributions licensed under CC BY-SA 3.0