I am writing a WCF service where I need to access the Hash Code of client certificates that are used to connect to the service.
I am looking for a property or method similar to Request.ClientCertificate from ASP.NET 2.0 days but cannot find anything that allows easy access to the client certificate.
Our service is set up such that it is running with SSL using basicHttpBinding and security mode of "Transport".
IIS has been set up to Require SSL and Accept certificates.
One thing to note is that our server certificate used to secure the endpoint is from a different CA to that of the client certificates - the client certificates are intended to be validated solely through custom code (thus the need to get the hash code of a connecting certificate).
I have created a custom implementation of the IDispatchMessageInspector to see if there is any access to a client certificate from there but to no avail.
Has anyone attempted this and had success before?
Looks like what the best option for you would be to implement a custom Certificate Validator for your service. This is basically a class that derives from X509CertificateValidator and is then registered through the config file.
There's more complete information on how to do this on this article.
For reference if anyone else attempts to apply client certificate authentication the following steps were required to get it to work (we are using basicHttpBinding within WCF for this instance and running in a local instance of IIS):
Set up IIS to use a HTTPS binding for the site and secure this in IIS with a server certificate
Within IIS change the SSL Settings for your site to Require SSL and Require client certificates (It must be Require - Accept will not work)
Within the WCF configuration ammend the basicHttpBinding and set security mode to "Transport" and the transport clientCredentialType to "Certificate"
Ensure that the root certificate (the one used to create any client certificates) is within the "Trusted Root Cerrtification Authorities" for the Local Computer on which IIS is running.
NOTE If you are in a development environment you may need to generate your own root certificate, the makecert command line application is very useful for this; simply run the following command:
makecert -n "CN=My Test Auth" -r -cy authority -a sha1 -sv "My Private Key.pvk" TestAuth.cer
This creates a certificate called TestAuth.cer (which needs to be added to the Computer's "Trusted Root Cerrtification Authorities") and a private key file called "My Private Key.pvk".
Now to generate a client certificate you can run this command:
makecert -a sha1 -n "CN=myConnectionCert" -ic "TestAuth.cer" -iv "My Private Key.pvk" -ss My
This created a certificate with a subject of myConnectionCert and adds it to your personal certificate store - when you now access the site (to view the service page for example) IE should prompt you to select the certificate - chose the one you have just created and you should see the service page as normal.
Related
I've always been an end consumer of HTTPS and have never really understood it that well but am looking to change that.
I am calling a RESTful web service over HTTPS. For example...
curl -X GET \
https://myCompanydns/rest/connect/v1.4/myEndpoint
With all my requests I send a basic authentication header i.e a username and password.
When I make these calls via my application I was expecting to have to add a certificate into like a jks (which I've had to do in the past) but on this occasion I've found that I can call the HTTPS web service without that.
For HTTPS to work I believe there is an SSL handshake? How is that happening successfully is this scenario without a jks?
Again, sorry for this beginner type question.
When doing a https://... request the client needs to verify that the servers certificate is the expected one - and not some man in the middle. This is done (among other things) by making sure that the servers certificate was issued by a trusted certificate authority (CA). Which CA is trusted is setup in the local trust store (i.e. local to the client). In the above call where no explicit trust store is given curl is using its default trust store. In the case where you've explicitly gave a jks you've provided the application with a specific trust store it should use.
For more on how the server certificates gets validated see SSL Certificate framework 101: How does the browser actually verify the validity of a given server certificate?.
I've read quite a few articles on the client certificate authentication in IIS but they mostly talk about the Required mode for the client certificate. In this case, the authentication is fully done on the web server side and the user is redirected to the error page in case the certificate is missing or invalid. What I need is to configure IIS to check the client certificate if it exists and pass the results as http headers to my backend. It can be easily done with nginx or apache web servers. The client authentication can be set up as optional. Then, the web server checks the certificate and pass the results of the check as SSL_CLIENT_CERT (PEM representation of the certificate) and SSL_CLIENT_VERIFY (the result of the check - SUCCESS, NONE,...) headers to the application backend. So, on the backend part, I can read the headers and use the values to do the actual authentication -- find a user in the database, issue an auth token. Is it possible in IIS? If yes, is there any documentation on how to bypass the certificate and the check state as http headers?
After a while, I'm writing an answer to my question.
IIS has to be set up with ARR extension to act as a reverse proxy. Then, the client certificate authentication can be enabled for the default web site. Here are several links to instructions how to achieve it:
https://blogs.msdn.microsoft.com/benjaminperkins/2014/06/02/configure-application-request-routing-arr-with-client-certificates/
https://blogs.msdn.microsoft.com/asiatech/2014/01/27/configuring-arr-with-client-certificate/
and couple of links to very solid explanations of the SSL/TLS handshake and certificates in general:
https://blogs.msdn.microsoft.com/kaushal/2013/08/02/ssl-handshake-and-https-bindings-on-iis/
https://blogs.msdn.microsoft.com/kaushal/2013/01/09/self-signed-root-ca-and-intermediate-ca-certificates/
https://blogs.msdn.microsoft.com/kaushal/2015/05/27/client-certificate-authentication-part-1/
Basically, the Application Request Routing (ARR) extension should be enabled for the IIS to act as a proxy. Then, you set up proxy bypass routes. Next, you need to set up a valid server certificate for the IIS server and use it in the Default Web Site https bindings. The certificate should be issued by a CA which certificate should be placed into the Trusted Root Certification Authorities and Intermediate Certification Authorities of the Local Computer. Then, you should require SSL in the SSL settings of the Default Web Site with the client certificates setting equal to Accept. In this case, any client that connects to the web server will be asked for a valid client certificate that has been issued by the same CA as the server certificate.
Actually, IIS sends a list of distinguished names of root issuers that are trusted by the web server to the client browser. The browser finds an intersection of this names with client trusted certificate issuers and looks for valid certificates that have been issued by the issuers in the intersection. After that, the user selects one of them (or none) and the selected certificate is checked against the CA certificate. If the certificate passes the check the request is "redirected" to the backend application with the certificate in the X-ARR-ClientCert header. The name of the header can be changed in the Server -> Configuration Editor -> system.webServer/proxy -> clientCertHeaderName IIS parameter. In case the user selects (or has) none of the required certificates, the request is "redirected" to the app backend without the header.
Seems, there is no need in the SSL_CLIENT_VERIFY header with the state of the check at all. If the certificate is valid it is passed in the header. If the certificate is missing the header is empty. If the certificate is provided by the client but is invalid then the request fails and is not "redirected" to the backend app server at all. Seems, it is a rare case but I have an example.
Imagine, a server certificate is issued by a CA with a distinguished name XXX, and there is a client certificate YYY (on the client computer) that is issued by a CA with the distinguished name XXX but those CAs are not the same (one or both of them are self-signed). In this case, the YYY certificate is present in the certificate selection dialog that is shown by a browser but the certificate doesn't pass the further validation against the real web server CA.
That's it. Also, seems IIS has no way to require (or accept) a client certificate for some app endpoints (addresses) only. I haven't found any other option apart from enabling in for the whole web site.
IIS ARR can also be configured with a client certificate for the backend or upstream server. In this case users connecting to this IIS do not need to provide the certificate as it will be attached by IIS automatically.
This configuration is available on IIS server level only.
When wcf service will use the certificate, then how the client, which will consume the wcf service will send the certificate to a wcf service. This idea is not clear to me that when wcf client will call wcf service first time, then how the client will send a certificate of service? Please discuss how people work with wcf & certificate.
Also guide me briefly that what are the steps we need to do to attach certificate with our wcf service?
How wcf client can send the certificate to wcf service when they make a call?
Do we need at all anything to configure for the certificate at wcf client end?
One guy told me
When use the certificate authentication in the wcf, then in the serive side and client side, you will need to install the service certificate and the client certificate. Then in the client side, the client will use the service public key to encrypt the message and send to the service, then the service will use the service private key to decrypt the message. And in the service side, it will use the the client public key to encrypt the message and send to the client. Then the client will use the client private key to decrypt the message.
if this is the limitation of certificate authentication that we need to install a certificate on both end, then we can use certificate authentication in very limited case. any tell me how to use certificate authentication when we have no control over the client who will consume the service.
when client is unknown they how they can send the certificate to our service.
actually i am trying to know how people manage to implement certificate authentication in real life when they do not have a control over the client who will be using their service. thanks
OK, you're looking for client certificate authentication of your would-be clients, which always includes SSL.
I've got a couple links for you to check out:
http://msdn.microsoft.com/en-us/library/ms731074(v=vs.110).aspx is the official version from MS that has good information, but not necessarily good instructions on getting this working.
and
http://architecturebyashwani.blogspot.de/2010/01/wcf-client-authentication-using-x509.html ... this is a better source in my opinion because it will walk you through the process of setting it up the certificates (self signed) you'll need for testing.
As far as controlling the issuance and certificates to client computers, that can be easy or difficult depending on how many client devices are involved and where they're located.
If you're talking about an internal implementation for server-to-server communication within a network, or perhaps a few PCs connecting to the host, that's not too difficult. In a nutshell, you copy a .PFX file (cert and private key) to the clients and host and set them up in the cert store (Like LocalComputer\Trusted, for instance). Then you set up the client and host WCF software to a) access the certificates and b) make get the host to deny access to non-authenticated users.
However, if you're talking about issuing and managing certificates for a thousand people walking around with iPhones, Androids and Laptops, that's a much more difficult proposition to control.
Here's a link, though, on setting up an internal certificate authority:
http://technet.microsoft.com/en-us/library/ff849263(v=ws.10).aspx
Added: This DOS scripting will create client auth certs, package them as a PFX and install them into a certificate store on the host.
On the host side you do this:
rem Comment -- creates client authentication cert, puts it in the currentuser\root authority and signs it based on the other certificate
makecert.exe -n cn=ClientAuthCert ClientAuthCert.cer -is root -sky exchange -pe -sv ClientAuthCert.pvk -eku 1.3.6.1.5.5.7.3.2
rem Comment -- make the pfx file that will allow you to copy certs around with private keys
pvk2pfx -pvk ClientAuthCert.pvk -spc ClientAuthCert.cer -pfx ClientAuthCert.pfx -f
rem Comment -- installs the certificate on the host in the localmachine / trusted people store
certmgr.exe -add ClientAuthCert.cer -c -s -r LocalMachine TrustedPeople
On the client side, you do this (after copying the .CER and .PFX files over to the client machine):
rem comment -- these lines install the certificates in the stores on the client device
certmgr.exe -add ClientAuthCert.cer -c -s -r LocalMachine TrustedPeople
Certmgr.exe -add ClientAuthCert.pfx -c -s -r CurrentUser My
Before anyone flags this as duplicate from the other barrel full of questions about WCF, I don't want MSDN links and blog article references. I can Google for myself, and have been at this for 3 days, so if all you have are Google links, please abstain.
I'm having a heck of a time with an IIS hosted WCF service using wsHttpBinding and a custom password authenticator. IIS is working fine for my standard ASPX and WCF non-secure services (using wsHttpBinding with security mode="None", but trying security mode="Message" or "Transport" requires an SSL certificate in the mix. I am to the point that I'm getting this error:
"The certificate 'CN=SignedByCA' must have a private key that is capable of key exchange. The process must have access rights for the private key."
By my research, either the service hosting my WCF service cannot access the private key file of my certificate, or I didn't generate the certificate correctly.
I generated the keys using:
makecert -n "CN=TempCA" -r -sv TempCA.pvk TempCA.cer
makecert -sk SignedByCA -iv TempCA.pvk -n "CN=SignedByCA" -ic TempCA.cer SignedByCA.cer -sr currentuser -ss My
I then imported the TempCA cert into my Trusted Root Certification Authority store, and I imported the SignedByCA.cer into my "Personal" store of the Local Computer. WCF can now see the certificate, but the above error indicates something either permissions problem or a key problem. I tried importing the cert into IIS Admin Service's Personal store as well, no luck.
By the way, I've added this to my web.config for the service:
<serviceCertificate
findValue="...."
x509FindType="FindByThumbprint"
storeLocation="LocalMachine"
storeName="My"
/>
I get the error from my client project when I add / update the service reference.
From my research, on Windows 7 I should be able to use the Certificate Manager and right click on the certificate in the MMC snapin and choose All Tasks -> Manage Private Key.. or some such. When I right click the certificate, I do not see that option, I only have these options under All Tasks: [Open, Request Certificate With New Key, Renew Certificate With New Key, Export...] This leads me to believe it is a cert problem and not a priv problem.
Thanks in advance.
After regenerating a .PFX file (PKCS #12 Certificate) http://msdn.microsoft.com/en-us/library/ms867088.aspx (create a .spc file with cert2spc.exe and a .pfx file with pvk2pfx.exe) and loading the .pfx file into the Certificate store, this exposes the "Manage Private Key" option. The original problem was following the MSDN instructions blindly and using a .CER public certificate file, which was not adequate for key exchange. The .PFX file does the trick. Now I'm able to add permissions for users / services to Read the key.
I also found that IIS7 on Windows7 was not running under the normal documented identity "NETWORK SERVICE" or "LOCAL SERVICE" but was running under "ApplicationPoolIdentity". So after I switched the identity, that issue resolved, (just another annoyance in getting WCF off the ground).
I need to secure a WCF service that uses netTcpBinding and connects directly with a Windows Forms based application. I only need it to be secured at the transport layer.
I'm pretty sure that I have it working locally, i.e. I can run the service locally, and connect to it with the client.
When I try to setup the service so that it is running on a server as opposed to my local machine, I'm having certificate issues. The error log says that the certificate must have a private key that is capable of key exchange and that the process must have access rights for the private key.
I'm using a development certificate created using makecert.
makecert -n "CN=MY COMPANY DEBUG" -pe -sky exchange Debug.cer
I must admit that I'm very new to using certificates. Does anyone have any pointers on how I can fix this, or a better way to use a certificate to add transport security to a WCF service using netTcpBinding?
Thanks.
Try this:
makecert -n "CN=MY COMPANY DEBUG" -pe -sky exchange Debug.cer -sv Debug.pvk
pvk2pfx -pvk Debug.pvk -spc Debug.cer -pfx Debug.pfx
You will then end up with three files, the .cer file (public key), the .pvk (private key), and the .pfx (key exchange with both). You can then install the .pfx file on the server like so:
certutil -p "" -importPFX Certificates\Debug.pfx
At the client end, you only need to install the .cer file. These installs (.cer and .pfx above) you can also do through the Certificates MMC snap-in (Start, Run, MMC.exe, then add the Certificates snap-in for the current machine).
Read this (covers https case but still may help) and this.
Since we are talking about transport-level security, I don't think your server process should know anything about certificate you are using to provide it.