How to revoke a client certificate in WCF? - c#

I'm developing a self-hosting WCF Service with this scenario:
wsHttpbinding
*Transport security layer
Client Credential = Certificate
I created a self-signed RootCA certificate and a "www.server.com" and a "www.client.com" certificates issued by the RootCA certificate.
This is the client environment configuration:
I need to install the RootCA public key in the Trusted Root Certification Authorities store and the www.client.com certificate in My store.
Like this everything is working.
But my question is, in this scenario described in MSDN example the www.client.com public key should not be in the TrustedPeople store of the server machine too? Because if I want to exclude a client I should have the control on the server side. Theres some configuration on WCF that allow me do that?
ps: In the MSDN link above, in the first paragraph theres this quote The server’s certificate must be trusted by the client and the client’s certificate must be trusted by the server. But this is not working.

I think that in order to fully control client authentication with certificates, you likely need to fully understand the certificate revocation process. The following article provides a good overview of Certificate Revocation, including the validation chain and CRL caching.
http://technet.microsoft.com/en-us/library/ee619754(v=ws.10).aspx
Regarding WCF configuration, you have access to the following config values that control client certificate validation:
X509ClientCertificateAuthentication.RevocationMode
X509ServiceCertificateAuthentication.CertificateValidationMode
http://msdn.microsoft.com/en-us/library/system.servicemodel.security.x509clientcertificateauthentication.revocationmode(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.servicemodel.security.x509servicecertificateauthentication.certificatevalidationmode(v=vs.110).aspx
Regards.

Related

Setting up custom certificate authentication in IIS 10 using OWIN

We are trying to setup multiple authentication using OWIN/Katana and the webapi will be hosted on IIS 10 with certificate authentication and windows authentication. I'm following this blog by Andras Nemes to setup my local client and server certificate authentication. Unfortunately, after setting up the Web API in IIS, when I try to access the website with the client certificate, I'm getting 403 Forbidden error which says that the certificate is not trusted or invalid. I'm not sure what is causing this issue.
I tried setting up my IIS by following other posts also, I've tried to add the website certificate to IIS and bind it with mylocalsite.local and tried with and without editing “system.webServer/security/authentication/iisClientCertificateMappingAuthentication”.
After searching a lot I found similar results but none of them worked. I'm not sure if it is because of the IIS 10 has a different workflow of configuring client server certificate authentication mechanism or is there a problem with my certificates.
Following are my self signed certificates, and I also have there pfx files.
RootCertificate:
RootCertificate.cer has been installed in Local Computer Trusted Root Certification Authorities as well as in Current User Trusted certificates.
localtestclientcert:
localtestclientcert.pfx has been installed in Current User under Personal certificates.
mylocalsite.local:
mylocalsite.local.pfx has been installed in Local Computer under personal certificates.
IIS Server certificates
website bindings
SSL settings of the website
EDIT 1: Modified "Trusted Certificates" to "Trusted Root Certification Authorities" for clarity
The solution is to add the root certificate to the trusted authorities using MMC (machine account) as indicated in this tutorial
https://learn.microsoft.com/en-gb/archive/blogs/asiatech/how-to-create-an-iis-website-that-requires-client-certificate-using-self-signed-certificates
If you import the certif to perosnal account using certmgr you'll get this error

How do I programmatically find whether the intermediate certificate was served by the web server?

My C# code uses HttpWebRequest to send requests to a web service via HTTP over SSL (https:// prefixed URLs). The service has it's coolservice.example.com certificate which is signed by certificate authority intermediate certificate which is in turn signed by the trusted root certificate authority certificate. The latter must be in the caller certificate store and marked as "trusted root", otherwise all that SSL trust chain thing makes no sense. However the intermediate certificate may come from either of the different sources:
the web server may serve it together with its own certificate (as in "here's my certificate and btw it was signed with this certificate which was signed with something you likely trust, please just check the signatures along the trust chain")
the caller may automagically retrieve the intermediate from the certificate authority (AIA protocol or something) - I know this because I've been interfacing with a web service which didn't have the intermediate certificate installed and "it just worked"
the caller may have the intermediate certificate installed in their store
I need to check that the web server properly serves (not only has in the trust store but actually serves the certificate) the intermediate while the SSL handshake is in progress. This test site even shows "sent by server" next to the intermediate. So I guess such check is possible.
How do I craft such a check with C# and .NET Framework?
So far I've only come across HttpWebRequest.ServerCertificateValidationCallback which accepts the web service certificate (X509Certificate object) and the trust chain (X509Chain object). The trust chain lists all the certificates in the chain however I cannot see anything detailing where the certificate was obtained.
How I programmatically find whether the intermediate certificate was server by the web server or it was obtained from elsewhere?

Fundamental of certificate based authentication

I searched a lot and found many answer on how to implement certificate based authenticate in wcf. But my questions are related to fundamental of it.
While implementing Certificate based authentication on production, does client provides its certificate which server needs to add on its trusted people store? Or server provides a certificate (signed by server).
I guess while configuring wcf server, we just configure certificate location and store. We never bind it with any domain. So any client that present this certificate can access my service. And in case certificate needs to be bound to a domain. They why cannot we just allow all requests from that domain.
When client calls a wcf service, it present its certificate. Does this certificate only carry public key? And can this certificate by stolen (as it travels on network) and used by hacker to consume the web service.
I have idea about how ssl woks. In case of ssl, browser take care of all this stuff but in case of wcf service (when we want to allow only specific client to access our service) how it gets managed.
Thanks In advance.
Let me make it simple :
I want to create a web service and i want that three clients (A, B and C) can use it. I want to authenticate these three clients by certificate. While setting up, do these clients need to send their certificates to me. Or I have to create certificate for them? Will client share their private key as well (while setting up)
Do I need to put these certificates into trusted people store?
When they request for webservice, they will present their certificate (with public key only). If they present it with public key only, hackers can steal this public key and request for my web service. How will my webservice distinguish between hacker/actual client.
While implementing Certificate based authentication on production, does client provides its certificate which server needs to add on its trusted people store? Or server provides a certificate (signed by server).
In a secure service, a server certificate is mandatory. Client certificate is optional. The server can be configured to ignore, accept, or require client certificates.
I guess while configuring wcf server, we just configure certificate location and store. We never bind it with any domain. So any client that present this certificate can access my service. And in case certificate needs to be bound to a domain. They why cannot we just allow all requests from that domain.
Not sure how you'd bind to a domain without a client certificate. You mean with reverse DNS lookup? That requires an IP address, and a malicious user can spoof it.
The typical means of restricting access via client certificates it to map one of the fields in the client certificate (typically the subject or domain) to a user account. You can have one-to-one mappings (each client certificate represents a single user) or many-to-one mappings (if the client has a certificate that is in a list, he is treated as a certain user). If the certificate isn't mapped, the user is treated as anonymous. More information here assuming you are using IIS.
When client calls a wcf service, it present its certificate. Does this certificate only carry public key? And can this certificate by stolen (as it travels on network) and used by hacker to consume the web service.
The certificate FILE that you handle during setup contains both the public and private key. The certificate itself is contained in that file; it contains a payload that includes the public key and a MAC signature, but does not include the private key.
The private key is put into secure storage and is never sent in any HTTP request. Only the certificate (and its public key) are sent over the wire. The whole file is not sent.
Edit to Respond to Further Questions
I want to create a web service and i want that three clients (A, B and C) can use it. I want to authenticate these three clients by certificate. While setting up, do these clients need to send their certificates to me. Or I have to create certificate for them?
During set up, a client certificate must be generated by a certificate authority (CA). You can actually serve the role as an intermediate CA (for production certificates) who derives his authority from a root CA (such as Verisign). In order to do that you must request a certificate from the root authority. They will issue you a certificate with its own public key, and give you a private key, so that you will have the ability to generate and digitally sign certificates of your own. You typically have to pay for this privilege.
In addition, you can become your own root CA! This is common during the development phase. Basically you generate your own public and private keys and start generating your own certificates. These are called self-signed certificates. The down side of being your own CA is that nobody will recognize your public key, so in order for anybody to use your certificates they would you have manually add you to their list of trusted root authorities.
Will client share their private key as well (while setting up)
No, nobody ever shares a private key with anybody, throughout the entire PKI. Ever. This is exactly why it is referred to as a private key. The only exception is when you are a certificate authority and you are generating a private key in order to create a certificate. In this case the private key must be carefully guarded during handling. It is never, ever sent over the wire as part of SSL communications.
Do I need to put these certificates into trusted people store?
Yes and no. If you are using a self-signed certificate, yes. If you are using a certificate that was signed by an CA that in turn has a certificate that was signed by a root CA, the root CA must also be in the list of trusted root authorities, but you probably don't have to add it. It should be there automatically. That is the whole purpose of using trusted root authorities-- everybody is supposed to know about them and should recognize their public keys. Root certificates are typically distributed to browsers automatically during installation and kept up to date using the browser's patch and update services.
When they request for webservice, they will present their certificate (with public key only). If they present it with public key only, hackers can steal this public key and request for my web service. How will my webservice distinguish between hacker/actual client.
This is a great question.
It's important to recognize that an SSL handshake includes a lot more than sharing certificates. There is also, among other things, a challenge/response step. Here's how it works:
Your server will generate a random number or time stamp ("challenge") and send it to your browser, challenging it to encrypt it. The browser will then encrypt the challenge using the private key (which it only has access to). This "response" is then sent back to the server for verification. The server uses the public key from the client certificate to decrypt the response. Since only the client has the private key, and since the public key is publicly known and verifiable (because it is contained in a signed and tamperproof certificate), the server can tell that the response had to have been encrypted by the client associated with the certificate. And because the challenge was generated by the server, and is different every time, a hacker cannot impersonate the client by replaying the response from a previous challenge.
While implementing Certificate based authentication on production, does client provides its certificate which server needs to add on its trusted people store?
Yes, if the server asks for it, otherwise no.
Or server provides a certificate (signed by server).
Always. These aren't mutually exclusive. Both can happen.
I guess while configuring wcf server, we just configure certificate location and store. We never bind it with any domain. So any client that present this certificate can access my service. And in case certificate needs to be bound to a domain. They why cannot we just allow all requests from that domain.
I can't make head or tail of any of that.
When client calls a wcf service, it present its certificate.
If the server asks for it.
Does this certificate only carry public key?
Yes.
And can this certificate by stolen (as it travels on network) and used by hacker to consume the web service.
No, because it only contains the public key.
EDIT Re 'Let me make it simple':
While setting up, do these clients need to send their certificates to me.
Only if they are self-signed.
Or I have to create certificate for them?
That's another possibility, but then you would have to become a mini-CA (Certificate Authority). Too broad.
Will client share their private key as well (while setting up)
Definitely not.
Do I need to put these certificates into trusted people store?
There is no such thing as a 'trusted people store'. There is a trusted certificate store, which usually only contains CA certificates. You only need to add the actual client certificates if they are self-signed. You might need to add their CA certificate if it isn't already there.
When they request for webservice, they will present their certificate (with public key only). If they present it with public key only, hackers can steal this public key and request for my web service.
I've already answered that. No.
How will my webservice distinguish between hacker/actual client.
They won't 'just' present their certificate: they will also provide a digital signature over it signed by their private key. Possesion of the certificate alone is worthless to an attacker. Without the private key they cannot even get past the TLS handshake. Your web service won't even see them.

.NET doesn't trust my self-signed certificate, but IE does?

I've got a self-signed certificate for testing in development. I've added it under the "Trusted Root Certification Authorities" folder in certificate manager, and when visiting the site under IE or Chrome it's accepted as valid (under Firefox it doesn't like the fact it is self-signed).
However, when my C# client tries to connect to call a webservice or to open an SSL socket, it get an exception saying "Could not establish trust relationship for the SSL/TLS secure channel with authority '[server address]'.". And even more annoyingly this doesn't happen when I debug via Visual Studio, it only happens when I try and run it from a test machine which has also had the certificate added to the trusted group.
What criteria is .NET using to validate my certificate?
Did you add the certificate as a trusted root authority under the Current User, a specific Service Account or under Local Machine? Most likely you only added the new root authority for the current user only, so any service that runs under a different account will not trust the certificate.

WebException Could not establish trust relationship for the SSL/TLS secure channel

My company has developed a .NET web service and a client dll that uses that web service. The webservice is hosted on our server over ssl and the cert is provided and signed by GoDaddy. We have some clients in a hosted environment that are getting the following error message from the client dll when it tries to access our web service.
System.Net.WebException The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
Our fix has been to have them open IE on the server, which is a challenge in and of itself for a lot of the hosted services, and go to the WSDL url. IE then prompts them with a security alert dialog. It says the cert date is valid and a valid name matching the name of the page, but was issued by a company you have not chosen to trust. When they click Yes to proceed, the client dll can then succesfully connect to the web service and operate as normal.
Does anyone have any idea why GoDaddy would not have been in there valid publishers list? All of the servers we have running has GoDaddy as a valid authority. I'm guessing, for security reasons, they've uninstalled the authority for GoDaddy, but not totally convinced that there's not some other underlying issue.
Unfortunately, I haven't had much luck trying to recreate this locally. If I go into Internet Options and remove the GoDaddy authorities and hit our service, ssl works just fine. I go back into the list of publishers and GoDaddy gets put right back in. So my second question is, How the heck do you get rid of GoDaddy so I can get an invalid cert warning?
Okay, last question. Is there a way in code I can tell the web service to ignore invalid certs. I've seen some posts on doing this programatically with WCF but not old web services.
I fixed this error by adding this line before calling the web method:
System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) => { return true; };
You may need to install on your servers the intermediate certificates used to sign your SSL certs.
Browsers will attempt to validate the SSL certificate by checking the validation of the chain of certs that signed the SSL cert. If the server doesn't supply the certificate chain with the SSL certificate, the browser may reject the SSL cert. (More of an issue for Firefox than IE). The root certificate must still be installed on the client machine for any of this to work.
VB.NET equivalent is
System.Net.ServicePointManager.ServerCertificateValidationCallback = Function(senderX, certificate, chain, sslPolicyErrors)
Return True
End Function
This is really more of a serverfault question, but I'll add what I can here.
The root cert authority list that windows machines normally trust is updated fairly regularly. This comes down as a windows update to IE. You can see MSDN for more information.
If your clients do not have windows update turned on or are actively ignoring windows updates, which is unfortunately very common for a lot of IT departments, then there's not much you can do other than switch SSL providers.
Basically, they need to get the certificate updates or you need to switch to a cert provider that has a high probability of already being trusted by the machines in question. Typically this means Verisign or Thawte. The third alternative is the route you've been going down: have them manually trust the root CA.
At the end of the day I hate the idea of changing an app in this way simply because the IT departments in question are morons but the real question boils down to how your company wants to handle this.
When you look at the Go Daddy Certification Path of that certificate on the web server, do you see Go Daddy Class xxx or Starfield Class xxx ?
And from your non-legacy client i.e Windows Vista upwards, what does the Go Daddy Certification Path display? Go Daddy Class xxx or Starfield Class xxx ?
And these clients that get the warning, are they legacy clients? i.e WinXP and older?
Root Certificate updates works differently as of Windows Vista.
http://support.microsoft.com/kb/931125
Root certificates on Windows Vista and later are distributed via the automatic root update mechanism – that is, per root certificate. When a user visits a secure Web site (by using HTTPS SSL), reads a secure email (S/MIME), or downloads an ActiveX control that is signed (code signing) and encounters a new root certificate, the Windows certificate chain verification software checks Microsoft Update for the root certificate. If it finds it, it downloads the current Certificate Trust List (CTL) containing the list of all trusted root certificates in the Program, and verifies that the root certificate is listed there; it then downloads the specified root certificate to the system and installs it in the Windows Trusted Root Certification Authorities Store.
You'll probably find that your Go Daddy Certification Path on the web server thinks it's Starfield Class 2 instead of Go Daddy Class 2 so you installed the wrong root certificate. It caught me out as when you view in on the web server it doesn't display a root certificate warning, download and install the Do Daddy class 2 root cert and remove the Starfield one and your problem should dissapear.

Categories