SOAP security negotiation failed after windows security update KB4056892 - wcf

I have a server which runs this WCF service, this service worked perfectly before the new windows security update KB4056892.
The client which uses the service cannot verify the certificate, if i remove the certificate security it works perfectly. Also if i remove the windows update it will work as usual.
I've tried to change the validation method without any luck.
The certificate is not outdated and tried to test the key with an certificate utility app. The certificate chain and private key was successfully tested.
<security>
<message clientCredentialType="UserName" />
</security>
"SOAP security negotiation with 'http://servernameproduction..' for target 'http://servernameproduction..' failed. See inner exception for more details."
Innerexception: The X.509 certificate CN=xxx, O=xxx, STREET=xxx, L=xxx, S=xxx, PostalCode=xxx, C=xxx chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. The certificate is not valid for the requested usage.
UPDATE: https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-0786

Related

Mutual SSL authentication with WCF: no CertificateRequest and CertificateVerify in handshake phase

I'm working on a WCF service that is to be consumed by a client that is not developed by me and also it's not .NET (possibly Java).
In any case, the service should support mutual SSL authentication, where both the service and the client authenticate with certificates X.509 certs at the transport layer. The certificates have been exchanged between parties at a prior moment.
My problem is that I cannot seem to get the right WCF configuration such that client certificate authentication works correctly. What I expect is that, as part of the TLS handshake, the server also includes a Certificate Request, as seen below:
Following this, the client should answer with a `Certificate Verify' among other things:
The (latest) service configuration is this one. I'm using a custom binding, with authentication mode set to MutualSslNegotiated.
<bindings>
<customBinding>
<binding name="CarShareSecureHttpBindingCustom">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="MutualSslNegotiated"/>
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
...
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" httpHelpPageEnabled="false" />
<serviceCredentials>
<serviceCertificate findValue="..." storeLocation="LocalMachine" x509FindType="FindByIssuerName" storeName="My" />
<clientCertificate>
<certificate findValue="..." storeName="My" storeLocation="LocalMachine" x509FindType="FindByIssuerName"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
The Server Hello part of the handshake looks like this for all service configurations I have tried, with no CertificateRequest.
Other things I should mention:
The service is self hosted and listening on a non-default port (not 443). The server SSL certificate has been bound to this port.
I have also tried a basicHttpBinding and a wsHttpBidning with security mode set to Transport and client authentication set to Certificate, with no results (same results actually).
Any ideas would be appreciated.
OK, after a few more tries I figured it out. Posting this in case others run into the same issue.
I should continue by mentioning that this behavior really needs to be mentioned somewhere on MSDN, in a location that is really visible for anyone looking for WCF security information and not buried deep in some tool's documentation.
The platforms where I've been able to reproduce and fix this: Windows 8.1 x64 and Windows Server 2008 R2 Standard.
As I mentioned, my issue was that I could not configure WCF security such that the service would require client certificates. A common confusion that I noticed while looking for a solution is that many people believe that the client can send the certificate if it has it, unchallenged. This is, of course, not the case - the server needs to ask for it first and, moreover, specify which CAs are allowed through a CertificateRequest reply.
To summarize, my situation was:
Service is self-hosted.
Service runs on HTTPS, on a non standard port (not 443 but 9000).
This meant that I had to create an SSL certificate binding for port 9000 by using netsh.exe http add sslcert. Well, the binding had been created but there was a catch. I only found the issue after running netsh http show sslcert just to check on my binding:
IP:port : 0.0.0.0:9000
Certificate Hash : ...
Application ID : ...
Certificate Store Name : MY
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
-->Negotiate Client Certificate : Disabled
The culprit was the last property of the binding, "Negotiate Client Certificate", documented here. Apparently, by default, this property is disabled. You need to enable it explicitly while creating the binding.
Recreating binding with the statement below solved the issue:
netsh.exe http add sslcert ipport=0.0.0.0:9000 certhash=... appid=... certstorename=MY verifyclientcertrevocation=Enable VerifyRevocationWithCachedClientCertOnly=Disable UsageCheck=Enable clientcertnegotiation=Enable
Prior to checking the bindings I tried hosting a simple WCF service in IIS and enable client certificate authentication from there. It was very curious to see that although there was no CertificateRequest issued by IIS, it still failed with a 403.7. Even IIS didn't create the binding with the appropriate parameters.
Anyway, now it works and this is how you can fix it.
Not to forget, the service configuration changed as well (the binding security) in order to allow certificate negotiation:
<customBinding>
<binding name="CustomHttpBindingCustom" receiveTimeout="01:00:00">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="SecureConversation" requireSecurityContextCancellation="true">
<secureConversationBootstrap allowInsecureTransport="false" authenticationMode="MutualSslNegotiated" requireSecurityContextCancellation="true"></secureConversationBootstrap>
</security>
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
I had the same issue when my bosses were questioning why was our IIS hosted WCF service which implemented "2 way SSL" (mutual certificate authentication) not observed to be sending "Certificate Request" in the TLS handshake. After some investigation, we finally found that the certificate port binding configuration for Negotiate Client Certificate is disabled.
Get the current binding information by running the below.
netsh http show sslcert
Get the certificate hash and the application GUID from the first record (or the relevant SSL port), then run the following netsh command using an administrator console on the IIS server.
netsh http add sslcert ipport=0.0.0.0:443 certhash=xxxx appid={xxxxx} clientcertnegotiation=enable
Note that if an existing binding already exists for the IIS address and port, the following error will be reported.
SSL Certificate add failed, Error: 183 Cannot create a file when that file already exists.
Run the delete command to remove the existing binding before retrying to add it back again.
netsh http delete sslcert ipport=0.0.0.0:443
After the reconfiguration, the observed Wireshark TLS handshake became as expected. However, in my opinion, this setting doesn't matter in the end as the client certification is used for authentication whether during the initial handshake or afterwards within the encrypted exchange and 2 way SSL is achieved.

SSL Certificate validation always pass

I'm trying to setup a self hosted WCF service, exposed in endpoint with https address, and I want just certain clients can call the service.
Client authentication should be done by certificate provided by client.
I'm in a corporate network, all certificates are issued by same authority, so i'm using certificateValidationMode="PeerTrust" in server side to identify authorized clients.
The server certificate binding to port is done.
Service binding configured as:
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
Service behaviour configured as:
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"></authentication>
</clientCertificate>
</serviceCredentials>
The client certificate is in windows trust (trusted people) in server side.
The server certificate is in windows store (trusted people) in client side.
Communication between client and servers works OK so far...SSL handshake OK...
but, when I remove the client's certificate from Trusted People on server side, the client still can call the service, and I'm expecting just the opposite:
"If client's certificate not in server trusted people store, then dont accept call."
all cache already removed, server restarted... client app still can call the service from same previously authorized client workstation.
any suggestions ??

WCF Routing with Message Security

I have a WCF service with Message Security Authentication.
I want to set up a routing service for Load Balancing.
For some reason it doesn't work, I've enabled includeExceptionDetailInFaults to see exceptions, so in the client I see:
The client certificate is not provided. Specify a client certificate
in ClientCredentials.
It seems that the certificate isn't forwarded from router->service.
Currently the client/router/service is on the same machine, so I have all the certificates, but if I deploy them on a different machine will the Router have to have the private keys?
In addition, if I want to establish a non-secured connection between the router and service (offload the security), how can I provide the Identity of the caller?
EDIT :
For all Client/Router(both server&client)/Server the security configured the same :
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false"
algorithmSuite="Default" establishSecurityContext="false" />
</security>
There are many articles that says Microsoft didn't support this scenario and it is true.
This article explains how to write your own custom solution to provide security to all client/router/service.
The client certificate is not provided. Specify a client certificate in ClientCredentials.
I have seen this error when the service certificate doesn't match the host domain name.
If you are still seeing this issue can you post some of your configuration entries?
1) As first try to set certificate in the client side by code.
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>("Service1_Endpoint");
factory.Credentials.ServiceCertificate.SetDefaultCertificate(
System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
"<SeriveCerificateName>");
If you really have problem with certificate you promptly get exception at the application startup.
2) If there is no exception then check thumbprints of the service certificate on both sides.
This blog post explains that Microsoft didn't support this scenarion-
http://blogs.microsoft.co.il/blogs/applisec/archive/2011/12/12/wcf-routing-and-message-security.aspx

How to force WCF client to send client certificate?

I'm trying to access a publicly-hosted SOAP web service (not WCF) over https, and I'm getting an error that I've never seen before. First, here are the facts:
This service requires client certificates. I have a certificate that is signed by the same CA as the server's certificate.
I know that the URL is available, as I can hit it in Internet Explorer. IE brings up the "choose certificate" window, and if I pick it (and ignore the server-host-name-does-not-match-certificate error), it goes on and gives me an HTTP 500 error.
If I open the site in Chrome, after picking the cert and ignoring the error, I get a normal error message about WSA Action = null.
If I open the site in FireFox, after ignoring the error, I get a page about how the server couldn't validate my certificate. It never asked me to pick one, so that makes perfect sense.
Now, the exception:
Error occurred while executing test 12302: System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'ihexds.nist.gov:9085'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
I've traced the interaction with WireShark, but because I'm not an expert in the TLS protocol, I could be missing clues as to what's going on. Here, however, is what I do see:
C -> S Client Hello
Contains things like a random number, date/time, cypher suites supported, etc
S -> C Server Hello, Certificate, Certificate Request, Server Hello Done
Contains the server's certificate, and a request for a client certificate
C -> S Certificate, Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
HERE IS THE INTERESTING PART -- The first part of this packet is the Certificate handshake, where I assume the client certificate would be, but there are no certificates present (Certificates Length: 0).
S -> C Alert (Level: Fatal, Description: Bad Certificate)
Well, yeah, there was no certificate sent.
My binding is set up as follows:
<binding name="https_binding">
<textMessageEncoding />
<httpsTransport useDefaultWebProxy="false" />
</binding>
My behavior is set up as follows:
<behavior name="clientcred">
<clientCredentials>
<clientCertificate findValue="69b6fbbc615a20dc272a79caa201fe3f505664c3" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
<messageInspector />
</behavior>
My endpoint is set up to use both the binding and the behavior. Why does WCF refuse to send the certificate when it creates the https connection?
I solved the problem, but I do not understand why this configuration change fixed it. I changed this line:
<httpsTransport useDefaultWebProxy="false" />
to this:
<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />
and magically it started working. I had understood that the requireClientCertificate "knob" was for server-side, so I hadn't tried it during my wrangling. Apparently I was wrong.
There should have been a CertificateRequest from the server, naming acceptable cert types and CAs. If your certificate doesn't match those it won't be sent.
It could be a problem negotiating which security protocol to use. Specifically im thinking that the server might not like WCF trying to use TLS 1.0.
To see if this is the case try to add the following before invoking the service
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3
This could be added either in client code or by placing it in an IEndpointBehavior

using Self-Signed SSL certificate with WCF ws2007FederationBinding

I'm at my wit's end, and I'm hoping you can help me. I'm trying to get active WS-Trust authentication going with WIF from a web application to a web service, using a self-signed certificate.
I've already tried the following:
1) Install certificate in machine certificate store under Trusted Root Certification Authorities, Personal, and Trusted People
2) Make sure 'Everyone' has full access to Crypto/RSA/MachineKeys folder
3) Override certificate validation with ServicePointManager.ServerCertificateValidationCallback, to a method that just returns true. I can debug into this method and watch it return true.
And I STILL see this in the System.ServiceModel trace:
[0832] SecureChannel#66940002 - Certificate name mismatch.
[0832] SecureChannel#66940002 - Remote certificate was verified as invalid by the user.
And the application blows up with:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
That's because the ServerCertificateValidationCallback only does the SSL related part of the certificate verification.
So if it's still broken, this means there not only SSL at play here.
In fact WS-Trust is build on top of WS-Security and WS-Security does a signature of the headers of your message,. And the verification of that signature is not impacted by ServerCertificateValidationCallback.
You certainly have a second certificate signing the WS Security headers of your message.
There's a different piece of code that verifies if the name of that certificates matches the value in the identity node of the endpoint settings, as below :
<endpoint address="..."
<identity>
<dns value="PUT CN OF THE MESSAGE SIGNATURE CERTIFICATE HERE" />
</identity>
</endpoint>
If in addition the message signature certificate doesn't validate, you can disable it's validation by modifying "behaviors/endpointBehaviors/behavior/clientCredentials/serviceCertificate/authentication".
You set the certificateValidationMode attribute there to "None".
Or you set it to Custom, and will have then to implement your own validator, that derives from System.IdentityModel.Selectors.X509CertificateValidator and overrides the Validate callback.