Share via


WCF: Message Security limitation with TLS 1.2 protocol

 Issue: 
WCF Message Security breaks when using or forced to use TLS 1.1 or TLS 1.2 protocol.

Re-pro code: 
https://1drv.ms/f/s!ArgnWb8iHXB6gqcg43hmT5jjbKJ-IA

We can disable SSL 3.0 and TLS 1.0 inside server key and we get below failure stack.

Failure Stack: 
    29 clr!IL_Throw+0x184
    2a System_IdentityModel_ni!System.IdentityModel.SspiWrapper.AcquireCredentialsHandle(System.String, System.IdentityModel.CredentialUse, System.IdentityModel.SecureCredential)+0xd71ca
    2b System_ServiceModel_ni!System.ServiceModel.Security.TlsSspiNegotiation.AcquireDummyCredentials()+0x73
    2c System_ServiceModel_ni!System.ServiceModel.Security.TlsSspiNegotiation..ctor(System.String, Boolean, System.IdentityModel.SchProtocols, System.Security.Cryptography.X509Certificates.X509Certificate2, System.Security.Cryptography.X509Certificates.X509Certificate2, Boolean)+0xfc
    2d System_ServiceModel_ni!System.ServiceModel.Security.TlsnegoTokenProvider.CreateTlsSspiState(System.IdentityModel.Tokens.X509SecurityToken)+0x75
    2e System_ServiceModel_ni!System.ServiceModel.Security.TlsnegoTokenProvider.CreateNegotiationState(System.ServiceModel.EndpointAddress, System.Uri, System.TimeSpan)+0x41
    2f System_ServiceModel_ni!System.ServiceModel.Security.IssuanceTokenProviderBase`1[[System.__Canon, mscorlib]].DoNegotiation(System.TimeSpan)+0xd6
    30 System_ServiceModel_ni!System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(System.TimeSpan)+0x68
    31 System_ServiceModel_ni!System.ServiceModel.Security.TlsnegoTokenProvider.OnOpen(System.TimeSpan)+0xcb

Reason: WCF does have these hard coded values..
TlsSspiNegotiation tlsNegotiation = new TlsSspiNegotiation(String.Empty, SchProtocols.Ssl3Client | SchProtocols.TlsClient, clientCertificate);
     internal enum SchProtocols
    {
        Zero = 0,
        Ssl2Client = 0x00000008,
        Ssl2Server = 0x00000004,
        Ssl2 = (Ssl2Client | Ssl2Server),
        Ssl3Client = 0x00000020,
        Ssl3Server = 0x00000010,
        Ssl3 = (Ssl3Client | Ssl3Server),
        TlsClient = 0x00000080,
        TlsServer = 0x00000040,
        Tls = (TlsClient | TlsServer),
        Ssl3Tls = (Ssl3 | Tls),
    };

Problem documentation and plan for fix:
Problem will be addressed and fixed in new framework release 4.7
https://github.com/Microsoft/dotnet-apiport/pull/395
https://github.com/Microsoft/dotnet/blob/master/releases/net47/dotnet47-changes.md\#wcf

Workaround for existing framework 4.6.2
1. Add the configuration file setting:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=false" />
</runtime>
</configuration>

2. Get the private DLL from following location:
https://1drv.ms/f/s\!ArgnWb8iHXB6gqRCG5I4nCw1vWbz8g

3. Path to copy them:
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.IdentityModel\v4.0_4.0.0.0__b77a5c561934e089\
And
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.ServiceModel\v4.0_4.0.0.0__b77a5c561934e089\

More details:
Private build is added with support for TLS 1.1 and TLS 1.2 protocol.
untitled
I have tested the above private DLL for self host WCF service, but got new error when testing against IIS hosted WCF service.

Error for IIS hosted WCF Service:
untitled4

 Workaround:
We can try to set the "EstablishSecurityContext" and "NegotiateServiceCredentials" to false at Message Security level and it should help us use WCF message security over TLS 1.1 / 1.2 protocol.
 <message clientCredentialType="Certificate" establishSecurityContext="false"  negotiateServiceCredential="false" /><br>negotiateServiceCredential: 

A Boolean value that specifies whether the service credential is provisioned at the client out of band, or is obtained from the service to the client through a process of negotiation. Such a negotiation is a precursor to the usual message exchange.
If the clientCredentialType attribute equals to None, Username, or Certificate, setting this attribute to false implies that the service certificate is available at the client out of band and that the client needs to specify the service certificate (using the <serviceCertificate>) in the <serviceCredentials> service behavior. 
This mode is interoperable with SOAP stacks which implement WS-Trust and WS-SecureConversation.

If the ClientCredentialType attribute is set to Windows, setting this attribute to false specifies Kerberos based authentication. 
This means that the client and service must be part of the same Kerberos domain. This mode is interoperable with SOAP stacks which implement the Kerberos token profile (as defined at OASIS WSS TC) as well as WS-Trust and WS-SecureConversation.

***When this attribute is true, it causes a .NET SOAP negotiation that tunnels SPNego exchange over SOAP messages. The default is true.


I hope this information helps to use WCF Message security correctly with TLS protocol.

Thanks
Saurabh Somani