简体   繁体   中英

WCF WF Service, Could not establish secure channel for SSL/TLS with authority

I keep getting the same error when trying to access my WCF WF Service: "Could not establish secure channel for SSL/TLS with authority."

I have tried a bunch of stackoverflow/google solutions but no luck so far.

I've made a WCF WF Service that connects to a thirdparty that uses a certificate to verify. My Web.config looks like this:

<?xml version="1.0"?>
<configuration>
<appSettings>
  <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
  <compilation debug="true" strict="false" explicit="true" 
                            targetFramework="4.5.1"/>
  <httpRuntime targetFramework="4.5.1"/>
</system.web>
<system.serviceModel>
  <bindings>      
    <basicHttpsBinding>
      <binding name="binding1">
        <security mode="TransportWithMessageCredential">
          <message clientCredentialType="Certificate" />
        </security>
      </binding>
    </basicHttpsBinding>
  </bindings>
  <client>
    <!-- Test Endpoint -->
    <endpoint address="https://example.com" 
              behaviorConfiguration="endpointBehavior" 
              binding="basicHttpsBinding" 
              bindingConfiguration="binding1" 
              contract="ContractPortType" 
              name="Port">
    </endpoint>
  </client>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="true"/>        
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="endpointBehavior">
        <clientCredentials>          
          <clientCertificate findValue="SOMETHUMBPRINT" 
                              storeLocation="LocalMachine" 
                              storeName="My" 
                              x509FindType="FindByThumbprint" />
        </clientCredentials>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <protocolMapping>
    <add binding="basicHttpsBinding" scheme="https"/>
  </protocolMapping>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" 
                             multipleSiteBindingsEnabled="true" 
                             minFreeMemoryPercentageToActivateService="1"/>
</system.serviceModel>
<system.webServer>
  <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

The client is just a simple console running this:

using (var client = new ServiceClient())
{
     System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
     var msg = client.GetData();
     Console.WriteLine(msg);
 }

That has the following App.config:

    <?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <system.serviceModel>
    <bindings>     
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService"/>
      </basicHttpBinding>
    </bindings>

    <client>
      <endpoint address="http://localhost:55670/GetData.xamlx"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService"
        contract="Reference.IService" name="BasicHttpBinding_IService" behaviorConfiguration="endpointBehavior" />
    </client>

    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="endpointBehavior">
          <clientCredentials>
            <clientCertificate findValue="SOMETHUMBPRINT"
                               storeLocation="LocalMachine"
                               storeName="My"
                               x509FindType="FindByThumbprint" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

It would be great if somebody could help me out.

EDIT: So the thing that I can't seem to get working is the SSL connection needed between my WCF WF serivce and the thirdparty service. When I directly call the thirdparty service from a client then I can set the System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; but I can't find a way to do the same for my WCF WF service.

EDIT: So I can make it work by creating an activity and then calling that activity before I call the thirdparty activity and then it works, but there has to be a better way!

public sealed class SetTlsVersion : CodeActivity
{
    protected override void Execute(CodeActivityContext context)
    {
        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    }
}

I ran into a similar issue earlier this year and it turns out that some SSL certificates utilize TLS 1.2.

.NET 4.5 defaults the TLS version to v1.1. This can be changed in your code by the following snippet:

using System.Net;
// ...
// In your application startup flow, set the security protocol to TLS 1.2.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

The above should be invoked at application startup time ideally. After that, I think you'll be good to go.

Side note: .NET 4.0 targeted applications will need a slightly different trick to set the TLS version:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

And in .NET 3.5 and lower , TLS 1.2 is not even supported unfortunately. But in your case it looks like your targeting .NET 4.5 so your good to go on this front.

EDIT : I noticed in your client code snippet that you bit-wise OR'd the TLS versions, which is incorrect. It should be a single value, SecurityProtocolType.Tls12 in this case.

I'm assuming the underlying .NET Framework networking code was only using SecurityProtocolType.Tls in the end, which doesn't match what the SSL / TLS certificate supports.

Hopefully that helps.

Well the only way that I was able to do this sort of nice was with a HttpModule (thanks ajawad987 for the tip). I'm still convinced that this could (or should) be done in the Web.config only.

public class InitializerModule : IHttpModule
{
    public void Dispose() { }

    public void Init(HttpApplication context)
    {
        // Sets the TLS version for every request made to an external party
        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
    }
}

Web.config

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <add name="InitializerModule" type="WorkflowService.Helpers.InitializerModule"/>
  </modules>
</system.webServer>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM