Search code examples
c#wcfwcf-security

WCF "A call to SSPI failed, see inner exception"


We have an existing system that uses WCF and was working fine until yesterday, when suddenly it stopped working on both my machine and another developer machine.

I've setup system diagnostics in the client config to write a trace file and we see the following exception:

Throwing an exception 

**Basic Information**

Activity Name           Receive bytes on connection 'net.tcp://localhost:8004/'.
Time                    2016-01-06 13:38:45.3958
Level                   Error
Source                  System.ServiceModel
Process                 NServiceBus.Host
Thread                  219
Computer                RL-ZORO-LPT
Trace Identifier/Code   http://msdn.microsoft.com/en-US/library/System.ServiceModel.Diagnostics.ThrowingException.aspx


**Exception**

System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    System.Security.Authentication.AuthenticationException, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
         System.ComponentModel.Win32Exception, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Exception Type: System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Message: A call to SSPI failed, see inner exception.

Stack Trace:  System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorAsyncResult.CompleteAuthenticateAsServer(IAsyncResult result)
              System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorAsyncResult.OnAuthenticateAsServer(IAsyncResult result)
              System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
              System.Net.LazyAsyncResult.Complete(IntPtr userToken)
              System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
              System.Net.Security.SslState.FinishHandshake(Exception e, AsyncProtocolRequest asyncRequest)
              System.Net.Security.SslState.ReadFrameCallback(AsyncProtocolRequest asyncRequest)
              System.Net.AsyncProtocolRequest.CompleteRequest(Int32 result)
              System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32 bytes)
              System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
              System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
              System.ServiceModel.Channels.ConnectionStream.IOAsyncResult.OnAsyncIOComplete(Object state)
              System.ServiceModel.Channels.TracingConnection.TracingConnectionState.ExecuteCallback()
              System.Net.Sockets.SocketAsyncEventArgs.OnCompleted(SocketAsyncEventArgs e)
              System.Net.Sockets.SocketAsyncEventArgs.FinishOperationSuccess(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
              System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
              System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

Our server configuration looks like this:

<system.serviceModel>
    <services>
      <service name="ServerImpl.RACServiceImpl.RACService" behaviorConfiguration="BILLService.ServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="net.Tcp://localhost:8004" />
            <add baseAddress="http://localhost:8006" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <endpoint address="BILLService" binding="netTcpBinding" bindingConfiguration="netTcpBindingConf" contract="ServerImpl.Rsp.ServiceInterfaces.IRACService">
          <identity>
            <dns value="RACServer" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <client>
      <endpoint address="net.Tcp://localhost:8001/RMACService" behaviorConfiguration="ClientBehavior" binding="netTcpBinding" bindingConfiguration="netTcpBindingConf" contract="ServerImpl.Rsp.ServiceInterfaces.IRACService" name="IRACService">
        <identity>
          <dns value="RACServer" />
        </identity>
      </endpoint>
    </client>
    <behaviors>
      <serviceBehaviors>
        <behavior name="BILLService.ServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="false" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <serviceCertificate findValue="RACServer" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <clientCertificate>
              <certificate findValue="RACClient" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
              <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
            </clientCertificate>
          </serviceCredentials>
          <serviceThrottling maxConcurrentCalls="40" maxConcurrentInstances="40" maxConcurrentSessions="40" />
          <dataContractSerializer maxItemsInObjectGraph="2147483647" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="ClientBehavior">
          <clientCredentials>
            <clientCertificate findValue="RACClient" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <serviceCertificate>
              <defaultCertificate findValue="RACServer" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
              <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="netTcpBindingConf" closeTimeout="00:11:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="100" openTimeout="00:20:00">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <reliableSession ordered="true" inactivityTimeout="00:15:00" />
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="Certificate" algorithmSuite="Default" />
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
</system.serviceModel>

This is our client configuration:

<system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="netTcpBinding_RACService" closeTimeout="00:10:00" openTimeout="00:40:00" receiveTimeout="00:32:00" sendTimeout="00:10:00" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00" />
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="Certificate" algorithmSuite="Default" />
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
          </security>
        </binding>
      </netTcpBinding>
    <wsHttpBinding>
        <binding name="WSHttpBinding_IThirdPartyRACService" closeTimeout="00:59:00" openTimeout="00:59:00" receiveTimeout="00:59:00" sendTimeout="00:59:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
          <security mode="None">
            <message clientCredentialType="None" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"></message>
            <transport clientCredentialType="None" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="net.Tcp://localhost:8004/AMACService" behaviorConfiguration="ClientBehavior" binding="netTcpBinding" bindingConfiguration="netTcpBinding_RACService" contract="ServerImpl.Rsp.ServiceInterfaces.IRACService" name="IRACService">
        <identity>
          <dns value="RACServer" />
        </identity>
      </endpoint>
      <endpoint address="net.Tcp://localhost:8004/AMACService" behaviorConfiguration="ClientBehavior" binding="netTcpBinding" bindingConfiguration="netTcpBinding_RACService" contract="ServerImpl.Rsp.ServiceInterfaces.IRACService" name="IRACService1">
        <identity>
          <dns value="RACServer" />
        </identity>
      </endpoint>
    <endpoint address="https://localhost/ThirdPartyWebService/ThirdPartyRACService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IThirdPartyRACService" contract="IThirdPartyRACService" name="WSHttpBinding_IThirdPartyRACService">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientBehavior">
          <clientCredentials>
            <clientCertificate findValue="RACClient" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <serviceCertificate>
              <defaultCertificate findValue="RACServer" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
              <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
            </serviceCertificate>
          </clientCredentials>
          <dataContractSerializer maxItemsInObjectGraph="2147483647" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
</system.serviceModel>

If we set the security mode to "None" on both the client and the server then it works.

What can be wrong here?


Solution

  • It turns out that what was causing the problem is a windows update that happened that same day (strange coincidence). The update is kb3102467 (aka .NET Framework 4.6.1) - which will eventually find itself on the machine.

    As it turns out, the SSL certificate we are using uses RSA/SHA512, which from what I've read caused high CPU usage and was therefor disabled (there was a hotfix for this issue and registry information that I saw was added, but after kb3102467 it still happened).

    As a workaround (until we issue new SSL certificates) I have disabled TLS 1.2 in the following manner:

    1. Start regedit and browse to the following location: HKLM\System\CurrentControlSet\Control\SecurityProviders\SChannel\Protocols
    2. Create the following Key under Protocol: TLS 1.2
    3. Create the following two Keys under TLS 1.2: Client and Server
    4. Create the following DWORDs under both the Client and Server Key: DisabledByDefault and Enabled
    5. Under both Client and Server set the following: DisabledByDefault=1 and Enabled =0
    6. Reboot the server.

    That solved the problem without the need to uninstall kb3102467