C# in VS2010, using WCF, Hierachical Certificates and IIS6 - c#

We've been working a lot in an application developed in VS 2010, C#, and WCF. We use Transport as the security mode, and in the TransportSecurity Properties set to None and None.
We are hosting the service in IIS6. After working a lot we managed to make it work using https. The Certificate we used was a self created one, created with the selfssl.exe tool. After creating the Certificate and storing it in the "Trusted Certificates" list, we set it as the Server Certificate in IIS for our Site, and also do the "binding" between the Certificate Thumbprint and the localhost address with the 443 port, using the httpcfg tool.
Well, we also use the famous piece of code not recommended for production (we are aware of that) that enables the validation of a Certificate that is not issued by a valid Certification Authority. This piece of code we took it from the MSDN WCF Hands On Lab. In this piece of code we give it the CN=NAME of the certificate and it works.
Ok, we finally got it to work. This was all in development. Now we are in the testing stage and they agreed to use the piece of code that enables the certificate. The problem is that the Certificate that we need to use, after setting it in the IIS and setting it to use the famous piece of code, it doesn't work.
The error we get is this one (only showing the first part of the error and not the stack trace):
System.ServiceModel.Security.SecurityNegotiationException: Could not establish trust relationship for the SSL/TLS secure channel with authority '172.30.224.46'. ---> 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.
The new Certificate is issued by their own Certification Authority, and it has several differences in comparison with our Self-Generated one, for example the "Usage" properties are different, or for example our Certificate has a "Enhanced Usage" property and theirs don't.
The other great difference we notice in the Certificate is that theirs is part of a hierarchy of Certificates, where they have a Trusted Root Certificate, then an Intermediate Certification Authoity and the Certificate to use in the Server is under that Intermediate one.
Is a special configuration needed to support this kind of certificates that are part of a hierachy? What can you guys tell us about this? .... we need some help :S
We also made a test creating a Self-Signed Certificate and all the steps needed to set it up in their environment, and the application works.
Thanks for your help and attention,
Andrey Gonzalez

Usually you get this error when the server name stored in the certificate is different from the hostname you use on the client to refer to the server.
For example, your server certificate is issued for "yourserver.com" and you are trying to access it from the client using only "yourserver" or its IP address.

Related

Question: C# API Could not establish trust relationship for the SSL/TLS secure channel

I just got the following error while calling an API.
"Could not establish trust relationship for the SSL/TLS secure channel"
I fixed it with the RemoteCertificateValidationCallback class:
ServicePointManager.ServerCertificateValidationCallback +=
new RemoteCertificateValidationCallback(Helpers.CertificateHelper.ValidateCertificates);
And there I just applied a snippet of code found here: How to verify X509 cert without importing root cert?
Now its working fine, but.. Is this the way to go? Is it okay, or should I not use this method?
When your server checks the certificates on a request it will try to verify the entire certificate chain.
The code you used basically tells your server to skip validating the root ca. You should not do that because as Crypt32 said it leaves you more vulnerable to attacks.
If the error you receive tells you that you are missing the root certificates you should make sure that your server trusts those certificates
If this is a windows server you can install them in the Trusted Root Certification Authorities - Theres an explantion about it here
Be careful about which certificates you trust - make sure that your source can be trusted
If that does not work, you should post here the exact error you are getting and we might be able to understand the problem better

Access SignalR application running on localhost from browser

I have an application that can be downloaded from my website and run on user PC. This application doesn't do anything special and just allows the web page to access the scanner. It uses SignalR for communication.
Basically, I run SignalR server under WinForms application and have javascript client that tries to access it through http://localhost:8084/signalR.
Everything works fine when I use HTTP version of the web application, but fails, when I use HTTPS for my web application: Most of the browsers don't allow unsecured connections from a secure page.
So, I've created a self-signed certificate that is installed on user system during installation and it works fine for Chrome, IE and Opera, but fails for Firefox and Edge.
So I was thinking, is there a better way to access SignalR applications that are running on localhost from webpage under https?
There isn't a better way. You are correct in your understanding that "[m]ost of the browsers don't allow unsecured connections from a secure page". I believe there isn't a browser that will allow this. Therefore if you want to call out from a secured website, you must use a secured connection as well.
I don't know the issue you're experiencing with Edge, as I can confirm that it does work. Firefox will NOT trust a certificate in the cert store, even if it is a trusted root or has a trusted root certificate. You have to manually add an exception for this certificate. Details, or at least information that will let you find the correct method to do this, can be found here.
There are some things you have to do in order to make sure your certificate and configuration is correct. First, you have to have a well formed certificate with a public and private key and a well formed certificate authority cert with only its public key. By "well formed" I mean it must contain all information required by browsers for full trust, such as a Subject Alternative Name entry.
You can use OpenSSL to generate the CA, then use that to sign a certificate you will use for the SSL port. Export the CA's public key and the SSL certificate's public and private keys. Exporting the CA's private key is a MAJOR no no. That would allow third parties to create new certs from it and install them on your client's machine. The CA gets installed in the machine's Trusted Root Certification Authorities store. The SSL cert can go into the Personal/Certificates store.
Once you have these, you have to configure the URL/Port you will use for access and SSL using the netsh command line tool. Add a URLACL to allow the application to access the url and port (netsh.exe http add urlacl), and then assign the certificate to the port (netsh.exe http add sslcert ).
Having done all this, you should be good to go. The only real problems you should have are Chrome being very demanding about the configuration of your certificates and Firefox refusing to trust your CA certificate even though it is in your trusted certificate store. Bastard.
And for Edge, I can definitely guarantee if you do all the above it will work. If it doesn't, you need to consult the js console to see what errors it is throwing.

Manually trust SSL certificate in C#

I am developing an application in C# that will communicate with a server over HTTP and SSL. Is there some way that I can have the program trust the certificate supplied by the server? This certificate would be distributed together with the software, so that it can identify the server without involving an external CA.
Clarification: I want my client application to trust a single certificate that has been hard-coded in the client so that it will only ever trust my own server.
You can use BouncyCastle.
Load your CA certificate into BC usign DotNetUtilities class using the FromX509Certificate(X509Certificate) function
Load the public key from the server certificate into BC.
Call Verify on the server certificates public key
This way you check the signature of the certificate. Which is the safest way. And also gives you the possibility to update the server certificate without updating the client. (As long as the CA is valid off course)
Source of Verify here: http://www.bouncycastle.org/viewcvs/viewcvs.cgi/csharp/crypto/src/x509/X509Certificate.cs?view=markup Line:540
In my opinion, I don't think you can do this and trust that you have a secure channel. Someone correct me if I'm wrong, but the CA trust chain in SSL isn't to just to verify that the thumbprint is a particular value (or some other part of the certificate). It proves that the the client is communicating with the correct server (due to a shared CA key). This illustration is a good reference. Skipping step 3, will not allow the server to prove its identity to the client (throw certificate validation).
so that it will only ever trust my own server
SSL guarantees this by using a shared CA certificate (like verisign etc). Maybe I don't understand why you would choose not to just use SSL as it was intended.
EDIT:
As the_ajp points out in his answer, there are libraries (like bouncy castle) that will do a full verification on the certificate chain. These can be called manually.

Debugging certificate policy validation failures: "The remote certificate is invalid according to the validation procedure."

I'm trying to write a C# client that consumes a web service. The communication is encrypted. I have downloaded and installed the sites' certificate into that magic place where WinXP keeps them.
When I run my client I fail with "The remote certificate is invalid according to the validation procedure."
When I run certmgr.msc, the GUI informs me that the certificate has an invalid policy. The certificate has valid dates and the certification path is ok. The certificate does have a certificate policy with a policy identify integers interleaved with dots (like 1.2.30...)
Using code from the X509Certificate2.Verify Method documentation, I can see that the Verify message does indeed return false.
In trying to research this error, I found a reference in Brian Komar's Windows Server 2008 PKI and Certificate Security:
Policy validation. If the application that calls the certificate chaining engine expects a specific application policy or certificate OIDs in the certificate, and the required policy or OIDs are not contained within the certificates in the CA chain, the certificate chaining engine considers the certificate to be invalid.
I don't see that I'm setting any expectation of a specific application policy. I'm in the process of porting this WSE3 code to WCF so perhaps it is built in.
Any advice on how to run this down further? Is there really a problem with the certificate?
If the certificate is ok, do I need to configure or extend the CryptoConfig class to turn off checking the policy?
Any and all help appreciated.
You can always disable the validation by setting the ServicePointManager..::.ServerCertificateValidationCallback to a delegate returning true. This would give you time to track down any issues with the certificate.
One technique I've used to track these type of errors down is to visit the Web Service in a browser.
For example, if you have a Web Service at https://server/foo.asmx, drop that address into the browser of your choice, and you may get a more human readable interpretation of the error.

Using certutil to check certificate responses

I am having a lot of trouble setting up an X509 certificate scheme in C#.NET. SSL is enabled on the server and the connection is being made over SSL. Certificates are being added to the request's store via request.ClientCertificates.Add(). However, no client certificate is being attached to the handshake request (which I am both confirming by both checking the server's code through HttpRequest.ClientCertificate and by analyzing the handshake in Fiddler).
As nearly as I can tell, the problem here is that the server is not requesting a client certificate. The certificates are definitely in the outgoing request, but I see none on the handshake and none on the server side - they simply disappear into the ether. I'm aware of the semantics behind choosing a certificate (thanks to this page), but it hasn't resolved my problem. The CAs should be the same; I am using the same self-signed, private key secured certificate for each end of the test.
Apparantly I can use certutil.exe to check which certificates will be chosen when used with a given server certificate. This would be a huge help if I could figure out how to use it like this. Certutil is a big program that is poorly documented. Any help would be appreciated.
If you're using IIS serverside you MUST provide certificate that is trusted by your server. So you MUST add client cert' CA cert into server computer 'Root certificate authorities' storage. IIS doesnt work with self-signed certificates. It requests client cert providing list of CAs it trusts to.

Categories

Resources