BizTalk WCF-BasicHttp Identity Editor field clarification - wcf

I'm trying to make it so my Send Port which is of type WCF-BasicHttp, will send a client certificate that will be accepted by the IIS server of the WCF service.
So far, as far as I can tell, the Client Cert is being attached (because when I put the wrong thumbprint value in there, I get a "Client Cert not found error"). However, now I'm getting an error as such
System.Net.WebException: The underlying connection was closed: Could
not establish trust relationship for the SSL/TLS secure channel. --->
System.Security.Authentication.AuthenticationException: The remote
certificate is invalid according to the validation procedure.
Which to me, sounds like something in processing the IIS SSL certificate is not working.
This service
works fine when being called from another Winforms application, using
the same Client Cert.
is set to Require SSL
is set to Require Client Certificates
Have a look at the image below...the only way I was able to the WCF to recognize a client cert was being attached was through configuring the send port as such:
My question is, does this look correct? Notice the highlighted field, what is supposed to go in there? Is this the reason I'm getting the SSL/TLS error?
EDIT Or, do I have it all wrong, and the lower Certificate Reference area is not supposed to contain the Client Certficate?

So, it turns out, that in order to get it to work, I had to provide the Service's identity in the top portion. I noticed that putting anything in the Endpoint Identity dialog, after saving, a nice little bit of XML is written to the WCF-BasicHttp dialog after.
<identity>
<dns value="myserver.mydomain.ca" />
<certificateReference storeName="My" storeLocation="LocalMachine" x509FindType="FindByThumbprint" findValue="[thumbprint]" isChainIncluded="False" />
</identity>
with only the lower portion filled out as in my question above, it provides the <certificateReference> portion, but the <dns value="myserver.mydomain.ca" /> does not show up until you provide something in one of the textboxes in the "General" section. It worked when I provided either the DNS, or the Base64 of the server certificate.
So, I guess the answer is, once you fill out one of the sections, both are required, the send port is not going to automatically guess on the endpoint based on the address.

Related

How do I implement Client Certificate authentication the right way?

WCF is extremely extensible and has a lot of ready-to-use features, however I continue struggling with some topics and the more documentation I read, the more I get confused.
I hope to get some answers from the community. Feedback on any assumption or question is extremely welcome.
For the record: to really accept a single answer I should divide this post in multiple questions but it would lead to even more confusion.
I am pretty sure there are some real WCF experts online who can answer the few questions in this document all at once so I can accept a single answer as the real deal to setup clientcertificate authentication using IIS the right way.
Let me sketch the situation and partner request:
1: The partner requirement and the question to use a client certificate.
Partner X needs to call an API on my backend and they have the clear requirement to use Clientcertificate authentication.
They created the clientcertificate and provided us the certificate with only the public key since it seems only logic they keep the private key actually private and in their own system(s).
The certificate was imported on the local computer account and looking at the certification path this is valid. All intermediate certification authorities and in the end the root certification authority are trusted.
2: Our WCF serverside configuration
I have a serviceBehavior configured as such:
<behavior name="ClientCertificateBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="<serialnumber here>" x509FindType="FindBySerialNumber" />
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
</serviceCredentials>
</behavior>
I guess I made a first mistake here and should use ChainTrust to actually validate the certificate using its certification path. What do you think?
The service is configured as such:
<service behaviorConfiguration="ClientCertificateBehavior" name="<Full service namespace and servicename>">
<endpoint binding="basicHttpBinding" bindingConfiguration="Soap11CertificateBasicHttpBinding"
contract="<The interface>"></endpoint>
</service>
The binding looks like this:
It is a basicHttpBinding to force SOAP1.1 (according to the partner's specifications).
<binding name="Soap11CertificateBasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
3: Hosting the WCF service in IIS and the IIS configuration
We host our WCF services in IIS7.
We configured the folder in which the services reside to require SSL and to accept Client certificates.
Authentication-wise anonymous authentication is enabled.
The thing is that communication from the partner works and we were confident that everything was OK, however toggling the IIS-setting to 'require' client certificate shows us that all of a sudden it is no longer possible to successfully call our service.
Am I correct to assume that following things are not done correctly:
The serviceCerticate in the serviceBehavior is not really necessary. This is a setting used by the client. Or is it necessary to provide this certificate information for the service endpoint to match the certificate that's being send by the client?
For clientcertificate authentication to really work in IIS the certificate needs to be mapped to a user. This user should be granted permissions on the folder containing the services and all authentication mechanisms (anonymous, windows,...) should be disabled.
This way IIS will handle the actual handshake and validate the servicecommunication.
Or is it more a matter of extra security mapping the certificate to a user?
By setting 'Accept' on IIS we bypass the actual certificate validation between client and server.
All authentication mechanisms like 'anonymous' and 'windows' have to be disabled on IIS for the folder which holds the services.
In your scenario, you don't need to configure certificates in WCF, IIS handles those for you. You can clear the entire <serviceCredentials> block, because:
The <serviceCertificate> of <serviceCredentials> specifies an X.509 certificate that will be used to authenticate the service to clients using Message security mode, which you do not use, and the <clientCertificate> of <serviceCredentials> defines an X.509 certificate used to sign and encrypt messages to a client form a service in a duplex communication pattern.
See here how to map client certificates to user accounts.

Azure web role - Multiple ssl certs pointing to a single endpoint

Is there a way I can have multiple ssl certificates point to a single inputendpoint in a service definition? For example, lets say I have two url's.
service.foo.net/Service.svc
service.doo.net/Service.svc
I want both of these addresses to resolve to my windows azure service, but I'm not sure how to configure this in the service definition.
<Certificates>
<Certificate name="service.foo.net" storeLocation="LocalMachine" storeName="My" />
<Certificate name="service.doo.net" storeLocation="LocalMachine" storeName="My" />
</Certificates>
<Endpoints>
<InputEndpoint name="HttpsIn" protocol="https" port="443" certificate="service.foo.net" />
</Endpoints>
According to this MSDN article, each input endpoint must have a unique port. Is there any way to specify more than once certificate for this endpoint?
Unfortunately this is not possible. Azure is re-exposing an SSL limitation. The SSL limitation is interesting, and the reason you can't use v-hosts over SSL. Lets walk through an example:
You connect to https://ig2600.blogspot.com
That resolves to some ip address - say 8.8.8.8
Your browser now connects to 8.8.8.8
8.8.8.8 must preset a certificate before your browser will send any data
the browser verifies the ceritificate presented is for ig2600.blogspot.com
You send the http request, which contains your domain name.
Since the server needs to present a certificate before you tell it the host name you want to talk to, the server can't know which certificate to use if multiple are present, thus you can only have a single cert.
"Oliver Bock"'s answer may work for you and "Igor Dvorkin"'s answer is not valid anymore since IIS 8 with Windows Server 2012 supports SNI, which enables you to add a "hostheader" to HTTPS bindings and having multiple SSL certificates to different domains listening to the same HTTPS port.
You need to automate the process of installing the certificates on the machine and add HTTPS bindings to IIS.
I'm a Microsoft Technical Evangelist and I have posted a detailed explanation and a sample "plug & play" source-code at:
http://www.vic.ms/microsoft/windows-azure/multiples-ssl-certificates-on-windows-azure-cloud-services/
This post indicates you will need a "multi domain certificate", which seems to be a certificate that can match multiple DNS names in step 5 of Igor's answer. I have not tried it, but presumably this certificate can be uploaded to Azure in the usual way.

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.

"Cannot load the X.509 certificate identity specified in the configuration"

I transfered a workking WCF service from my development environment to the QA environment, including the certificates (Root Authority, Root Auth revocation list, Service certificate - including its PK).
Afterward I located the private key usihg 'FindPrivateKey' and gave all the relavent accounts full permissions to access the private key file at the file system level.
My app crashes with a Unhandled Exception: System.InvalidOperationException: Cannot load the X.509 certificate identity specified in the configuration.
I am stumped, I think I covered everything, but obviously not...
I have tried this on a Windows Service Host as well as a Console App Host. Same issue.
I ran into this same error in a simple WFC service written with VS2010 SP1 on Win 7. The fix that I found was to add
<dns value="localhost" />
to the <identity> section of app.config
Source: http://social.msdn.microsoft.com/Forums/en-AU/wcf/thread/439539ef-e8d7-4e7d-b36e-b80acd401606
this works for me :
<identity>
<certificateReference storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="xxxxxxxx" />
<dns value="localhost" />
</identity>
Here's a tutorial explaining how to create a certificate that is supposed to remedy this problem:
Codeplex WCF Security: How To Create and Install Temporary Certificates in WCF for Message Security During Development.
Hope that fixes what you needed - even though you asked this 6+ months ago!
Regards,
Joe
Does your certificate common name match your host domain name?
I'm new to WCF and ran into this issue today when creating a simple WCF service. Just want to share some thoughts:
1. Fixing the issue - If you've read all other answers before Joe's (above) you'd know how to fix the issue ;) without the certificates
2. Fixing the issue with Certificates - I want to thank Joe for sharing a great link "How To: Create and Install Temporary Certificates in WCF for Message Security During Development"
Additionally: You can download WCF samples from Microsoft website.. You'll find a tool called 'FindPrivateKey' used in the above link