WCF - x509 Certificate from Smart Card - 'Cannot Verify Signature' - wcf

I have a WCF service running on IIS6 which is configured with a WSHTTPBinding using the "Transport with Message Credentials" security setting (with the transport client credentials set to 'None' and the Message set to 'Certificate'. This is being consumed by a .NET client that was created through the auto generated code by consuming a service in VS 2010.
In my development environment, I created a certificate to act as both the service cert and the IIS SSL certificate, and since I was lazy, I exported the certificate for use with my client application. Everything works great in that configuration, but that is not the target environment. The idea is to have users utilize their smart cards to access this service. The server will not be on the same domain and LDAP is not allowed, for now.
The problem is that now I got this in a test lab and set up an environment where the SSL certificate was issued by the same CA as the user's certs, and I have created a custom x509 Cert validator and service credentials, but after the initial call to my validator, something is happening in between the hand off and kicks out an error on the service trace log saying, "Error verifying message security" with an inner exception of "Cannot verify the signature". Since is is coming through my custom validator and I got the message logging up, everything looks fine on the SOAP side and I am getting the certificate through on the other side. I have made sure that every cert that I am trying to use is in the "Trusted Users" store and even tried exporting the certs and putting them in the local computer "Personal" store, with no luck.
I have a feeling that I do not fully understand the use of the service certificate and the client certificate in the web.config file. Can someone please help me out here?

Ok so I have managed to answer my own question with some help from my coworker. After we sat down together and started to run a bunch of questions by me and doing some random google searches, we decided to change something in the configuration that surprised me.
So to finish my question up top, I had the message credentials set to "Certificate" with the encryption algorithm suite set to "TripleDesSha256Rsa15". Turns out that the certificates on the smart card, or the card itself, would only support Sha1 (which was not an option with everything else). When we changed the setting to "Basic256", everything started working. I eventually was able to set it to "TripleDesRsa15" and it continued to work.
Basically, WCF sends the certificate up without a private key, because it cannot access it with that encryption algorithm. WCF DOES NOT throw an exception with this when trying to access the certificate, it will only throw it on the server side with the exception "Could not Verify Signature". Kind of wish it would say "There was no signature" because that would have been a bit easier to track down. I don't know if anyone will ever find this useful, but if you do and can find a reference to the "Proper" way of using Smart Cards with WCF, please post it with a ref.
Overall, check your encryption algorithm that you are trying to use, and make sure it works with the smart cards/certificates that you plan on using.

Related

WCF Service Could not establish trust relationship for the SSL/TLS secure channel with authority

I have my WCF service running in HTTP. I want to make my service run in HTTPS. I did this in my local with self seigned certificate and its working fine. But I'm getting
"Could not establish trust relationship for the SSL/TLS secure channel with authority"
error when I deployed my code in QA environment and created Self signed certificate for the same. I found some solution to validate the certificate at client side (Link). But I'm looking for some solution to fix this from server side. I don't want to disturb the client.
I suspect the error reflect that the client does not recognize your self-signed certificate or the underlying certificate authority. As such, until the client adds the client certificate to their certificate store or otherwise trusts the certificate, the only way they will be able to access the service is via a validation workaround like the one reflected in the link you included.
In order to determine the underlying cause of the issue, you may want to enable WCF Tracing and review the exceptions (especially inner exceptions).
My team supports many WCF connections protected by mutual certificate authentication. We have noticed that the error top level error may not provide as much information as the inner exception. Just yesterday, I had a site with that exact error. When we looked in the trace file, we saw an inner exception revealing that the certificate had not been deployed to the certificate store in the proper location. A few days previously, the “could not establish trust relationship” error had an underlying inner exception that revealed the certificate had been revoked by the certificate authority.
Hope this helps.
Regards,

Can't upgrade Azure deployment using Management REST API (SSL certificate issue)

I'm currently working on an automated deployment process for a hosted service for Windows Azure. The creation of the .cspkg and .cscfg files works perfectly using a call to msbuild. Now I'm writing a small .NET console app that should deploy these files to Azure using the Management REST API.
There is no problem concerning the API itself. I can send a request to the API using one of my management certificates. I upload the .cspkg file to Azure BLOB Storage and then try to call Upgrade Deployment. But every time I try, I get a "400 Bad Request" response stating that the certificate with thumbprint xy was not found. This certificate is the SSL certificate (not a management certificate) I'm using for HTTPS for my custom domain (DNS CNAME).
And now, the whole thing gets interesting:
When I deploy the files using the "Publish" command in my Visual Studio, there is no problem. (I compared the .cscfg/.cspkg files from VS and from my msbuild output: apart from a few GUIDs, they're identical). And furthermore, using the Silverlight Management thingy in my browser, I can even upload my generated files that could not be uploaded using the API.
When I retrieve a list of all certificates using the List Certificates call, the certificate which is said to be missing is apparently there. I can also retrieve its data using the Get Certificate call.
So why does Azure keep telling me that the certificate was not found when using the Upgrade Deployment call? Did anyone experience something similar? Has anyone the hint for me? Thanks in advance.
P.S.: This is what Azure says when I use the API:
<Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Code>BadRequest</Code>
<Message>The certitficate with thumbprint 7b232c4a2d6e3deadbeef120d5dbc1fe8049fbea was not found.</Message>
</Error>
P.P.S.: Yes, the word in the response is certitficate, not certificate.
OK, after using the List Subscription Operations API call to find out what Visual Studio calls to deploy apps, I found the solution.
Turns out that the URL I used for the API request was wrong, but: with all due respect, I blame Microsoft for lousily documenting its Azure Management API.
In their documentation, they write the URL to use is:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>/deploymentslots/<deployment-slot>/?comp=upgrade
And the description is the following:
To generate the request URI, replace <subscription-id> with your subscription ID, <service-name> with the name of your service, <deployment-slot> with staging or production, and <deployment-name> with the unique name of your deployment.
What they forgot to mention is, that you have to use the DNS Name of your service, and not the Name! They could at least return an appropriate error message telling you that the service name is invalid, non-existent or doesn't belong to your subscription ID, instead of complaining about some certificate issue.
Thank you Microsoft, that cost me more than two days.
The error indicates that you have not uploaded that certificate into the hosted service's secret store. Visual Studio might be doing that automagically for you, but if you want to replicate it programmatically, then use the Add Certificate API call and upload the PFX into the deployment.
You can see '400 BadRequest - The certificate with thumbprint XYZ was not found.' appear in the CreateDeployment or UpgradeDeployment scenario for the following reason (which I just debugged):
You use the same certificate for subscription management as you do for e.g. SSL or Remote Desktop password encryption in your hosted service. You therefore will use the certificate with thumbprint XYZ to authenticate your service management REST call that creates the deployment.
When specifying your deployment parameters you pass in your CSCFG which references that same cert by its thumbprint, because it needs to configure Remote Desktop/SSL etc.
That cert is not yet added to your hosted service certs.
In this case the 400 Bad Request error really is telling you that you have a bad request, because the certificate in your CSCFG is not yet attached to your hosted service. The confusion arises (for me) because, since its a multi purpose cert, you misinterpret the error message as referring to the authentication of the request, even though you are not getting 401.

Separating as a client the server's transport and message signature certificates with WCF

I am currently in the process of integrating a WCF client into a java web service. The server requires the client to authenticate via certificate using SSL and the message to be signed.
I have successfully sent the message to the server through SSL, Signed, etc. However, the server response message is also signed but with a different certificate than the one used to authenticate the server.
The WCF client doesn't like this behavior. It failed with the message: "The incoming message was signed with a token which was different from what used to encrypt the body. This was not expected." The problem is described here in detail.
Looking around on Google I found it is possible to decouple the clients transport certificate from the singing certificate by implementing ClientCredentials and other security related classes, and adding a new extension. You can read all the details about it here. However I'm having some trouble figuring out where exactly do i have to extend to provide this same behavior for the server's certificate on client mode.
Any help on the subject or reference would be appreciated.
Thanks in advance.
Have a look here
This shows you how to create an custom ServiceCredentialsSecurityTokenManager that allows you to specify the various message signing and encryption certificates for requests and responses to and from the server.
I emphasise message because the problem as you describe it appears to me to be message security validation. The transport security is seaperate from the mechanism used to validate the message security, i.e. the message signature and message decryption.
Ignore the transport security as this is lower down in the WCF pipeline and appears to be working working correctly from your description. A seaperate concern is the message security. It appears that you need to be able to use a certificate for decrypting the response and a certificate for verifying the signature. The above article shows a example for enabling this type of certificate managment, it does detail how you could create behaviours and extensions to apply this to your client that is a seaperate concern. This depends on how you want to configure your proxies i.e. through code or through configuration.
The example article you linked too is not a complete implementation for what you require, it only provides for a certifiate for signing and a certificate for the transport client credentials.
You could create a hybrid ServiceCredentialsSecurityTokenManager that provides the transport certificate and the signing and decryption, this should be clear enough from looking at the SecurityTokenRequirement documentation

Verifying caller/server in WCF

My scenario:
Many WCF clients which are in environments outside of my control
Server will either be mine OR in an environment outside of my control
So worst case the client and the server is outside of my control. More specifically, I might assume that someone hosting this code could try to maliciously impersonate either the server or the client (the server being more likely). However, the client needs to verify that the server is my code and the server needs to verify that the client is my code. I've seen all the recommendations to use certificates; however, is that an option given my scenario?
One approach I've considered is to write an IClientMessageInspector and an IDispatchMessageInspector to set and verify a custom SOAP header on both sides. I would create an HMAC signature based on a secret key contained within the source code (assume I have a way to keep this hidden) and then verify the digest based on the message body.
I feel like this would work; however, I feel like there might be something more out-of-the-box that I'm missing here. Am I close, way off track? Thanks for any guidance!
Certificates are definitely the way to go in your situation.
Your server will easily be authenticated by clients because it will provide a certificate known to each client, SSL is a good option here.
The server will also be able to authenticate clients by requesting that every client should provide a certificate (server can check for a specific issuer of the certificate - your own issuer in that case).
Now you just need to correctly manage/secure your certificate server to make sure that it won't be compromised.
I don't think there is anything out of the box to do this, simply because it is an unusual requirement for the server to verify that the code on the client calling the service is authorized code.
Generally, it is sufficient to establish trust as follows:
Server has a certificate and service uses SSL - this way clients are confident that they are connecting to the correct server machine.
Clients provide authentication details (eg username/password, certificate etc) to the server so the server knows the connecting client can be trusted.
You are attempting to go the extra step to verify that not only are the users/machines verified, but also that the code running is verified - this is simply overkill. If the code running is not verified, either:
One of the machines has been compromised, in which case you have bigger issues to worry about.
One of your users has written code against your service and is using it 'illegally'. This should not be a problem if your service only allows authorized users to perform 'dangerous' operations.

Can you get a client to trust a Server certificate without needing it to be a Registered Trusted Certificate?

I have a WCF Server Deployed through IIS. I want to Create a Certificate for it. I could do this by making the server a certificate server.
But then when the client connects to that server I want the client to automatically trust the certificate without having to register that the server as a "trusted authority".
Is this possible?
All this seems a lot of work to put username password protection on a WCF Service!
The short answer is no the client will need to add the server cert root as a trusted authority.
The slightly longer answer is that there is a workaround for needing to implement transport security in WCF when using message based authentication - this workaround is usually used when you want to rely upon another security mechanism that the WCF server is not aware of, like an ISA server providing SSL.
Have a look at Yaron Naveh's post. The essential idea is that you create a transport binding that pretends that it is secure.
With all that, you still need security (you don't want to send your creds in the clear) and so will still need a trust chain for your cert. So, it may not actually help you, but hopefully it gives you some options to consider.
Edit
Sorry if my answer was misleading. The server certificate root cert must by in the client trusted store. My additional detail was giving another option for providing the security (you can use an ISA server with a trusted cert to give your SSL connection)
In a similar situation to yours (needing secure communication when pushing client applicaitons to non technical customers) I have programatically installed the needed root certs.
Here is an SO post that details how to do that: How can I install a certificate into the local machine store programmatically using c#?
You can if you add this to your code but be aware of what you are doing!
System.Net.ServicePointManager.ServerCertificateValidationCallback += ( se, cert, chain, sslerror ) => { return true; };
Well if there would be such a way, it would be a security hole.
If a certificate is not linked to a trusted authority it is easily forged. So your choice is either to link it one way or another (directly or through a parent certificate you control), or configure your client so that it does not require the certificate i.e. using http rather than https.
Just keep in mind that it leaves your clients open to a variety of attacks
Edit
One of the possible attack scenarios is a man in the middle attack - a program inserts itself between your service and the client and channels the information though itself. This way the intruder has complete control over the information flow.
It can make copies of passwords or it can "adjust" the results in both directions any way it wants. The only thing which prevents this from happening is the certificates. But if they are not rooted, they can be forged.