tomcat client authentication using clientAuth=want - authentication

My application requires client authentication for a specific URL, after client authentication succeeds the application itself also does some verification on the client certificate subject (using spring security x509 filter). I wanted to configure tomcat to force client authentication (clientAuth=true) for the specific URL, but based on this post it seems I can't do this only using tomcat - configure tomcat for client authentication only for specific URL patterns.
My question is, if I use clientAuth=want, will the following be as below when the server requests a certificate:
If device has an identity certificate but not trusted by the CA configured in tomcat truststoreFile, no certificate will be passed and the request will fail in the spring security filter (certificate will be null)
If device has an identity certificate trusted by the CA configured in tomcat truststoreFile, but is invalid (not sure what validations are done) or expired, either the authentication will fail in tomcat (before the security filter) or as in option 1 no certificate will be passed and the request will fail in the spring security filter (certificate will be null)
Is there a security hole I may be missing using this configuration of want + security filter? I guess the question is - if a certificate is eventually passed from the device to the server, the server will always validate it (not expired, trusted etc) even when using clientAuth=want and will not allow the client to continue if the certificate is invalid? The case where no certificate is passed is covered by the security filter that will check the certificate is not null..
Thanks!

Your assumptions in both 1. and 2. are correct. Tomcat will not allow untrusted or invalid certificates through to your application. If you get a null certificate, you can assume that either no certificate was passed, or an untrusted/invalid certificate was passed.
On the project I am working on we have the same requirement as you: client certificates for certain URLs only. We found out by experimentation how "clientAuth=want" works.

Related

Cannot get mutual authentication with Keycloak and OpenLDAP working

I've been attempting to get mutual authentication working between Keycloak and OpenLDAP. I've configured the truststore on Keycloak under security realms, which works. I can view the certificate on requests. I've also configured OpenLDAP's truststore/keystore and set it to demand a client certificate. When using ldapsearch I can provide Keycloak's cert which allows me to connect. I've also verified that Keycloak accepts OpenLDAP's cert by changing OpenLDAP to not demand a client certificate, which allows Keycloak to connect (albeit after fixing the truststore). At this point, it appears everything is fine except Keycloak doesn't present it's certificate while acting as a client, and I get the following error in OpenLDAP.
TLS trace: SSL3 alert write:fatal:handshake failure
TLS trace: SSL_accept:error in error
TLS: can't accept: error:140890C7:SSL routines:ssl3_get_client_certificate:peer did not return a certificate.
Unfortunately I cannot share details about the configuration or environment beyond the above due to project constraints.

Confusion about HTTPS --> How is SSL handshake happing

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?.

How to setup IIS to verify a client certificate and pass it to the backend as an http header?

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.

Issuer details are not valid. Issuer details should be registered in advance

I am trying to run a test of the SAML2 SSO using WSO2 Identity Server 4.0.0 M7 but am not successful.
I tried to use the 3.2.3 binary but ran into the bug about long hostnames and the identity.xml file (http://stackoverflow.com/questions/9600392/unable-to-configure-wso2-identity-server-for-openid).
These are the examples I'm using:
http://sureshatt.blogspot.com/2012/08/saml20-sso-with-wso2-identity-server.html
http://wso2.org/library/articles/2010/07/saml2-web-browser-based-sso-wso2-identity-server
I've stood up a new Tomcat7 server and configured it for HTTPS, which works cleanly in the browser. The certs are signed by our trusted enterprise CA and both the private key and chain certs are installed.
Same for the WSO2-IS host which has a new wso2carbon.jks with the private key signed by the same CA. I've exported the host cert from wso2carbon.jks and imported same into the client-truststore.jks. The trusted CA-signed certs are also in client-truststore.jks (at this point just to be sure). They are also in wso2carbon.jks (used to trust the CA reply).
I've changed the HostName and MgtHostName in carbon.xml to match the CN in the private key; the Carbon console comes up cleanly with no SSL issues and I can log in using the 'admin' user with no problem. From there I've updated the SSO configuration using the above example links as guides. That works with no errors.
When I go to each site (e.g., saml2.demo, avis.com, etc.) they redirect perfectly to IS to authenticate. However when I log in I get the error in the log "Issuer details are not valid. Issuer details should be registered in advance". And then I'm stuck.
What have I missed?
Have you done the 5th step of the topic 2 Configuring the WSO2 Identity Server ? Please check the value you've registered as the Issuer is as same as the one that comes in the SAML Authentication Request message.

403.7 IIS 7.5 SSL client certificate authentication issue

I am testing a web service with an external partner using 2 way SSL under IIS 7.5. I am requiring SSL, requiring a client cert, and using one to one mapping to authenticate to a domain account. I have configured everything and it works fine on our network (I am able to provide a client cert, get authenticated and invoke the service from browser and test harness).
From outside of our network (in most cases, see below), I am getting a 403.7 error. I have gone through the machine level certificate store and made sure the certificates and CAs are trusted.
Here's the weird thing. I obtained a Type I cert to test from home (and got 403.7 like our intended partner is). So I setup Fiddler to debug SSL and send my certificate, and this works for some reason. I setup a test harness to pass the exact same certificate, and got 403.7. I test in my browser (IE 9), don't get a prompt for a client cert, and get 403.7.
Any help appreciated.
Bill
Last time I checked, IIS was using re-negotiation (by default) to get the client certificate: there is a first handshake where the server doesn't request a client certificate, followed by another handshake (encrypted this time) where the server requests the certificate (via a TLS CertificateRequest message). This will prevent you from seeing anything from Wireshark, unless you configure it to use the server's private key and decipher the traffic (note that this only works with some cipher suites).
One way to see the client-certificate negotiation is to configure IIS to use initial client certificate negotiation, using netsh and clientcertnegotiation=true (which is about initial negotiation). At least the CertificateRequest and the certificate will be sent in clear during the handshake, so you should be able to see this with Wireshark.
If the client isn't sending a certificate to the server as a response to the CertificateRequest, you'll still see an empty Certificate message from the client.
If you don't export the private key with the certificate to use with Fiddler or whichever other client, there is no chance that it will be able to use the certificate. It may at best try to send the certificate, but the handshake will fail (since the CertificateVerify message needs to be signed by the client's private key).
I guess you may encounter a problem whereby:
not presenting a certificate is accepted by the server (it's effectively optional),
presenting an invalid certificate makes it fail and causes this 403.7 status code (many servers and SSL/TLS stacks would implement this as a fatal error, but TLS specification doesn't say that unsupported_certificate, certificate_revoked, certificate_expired, certificate_unknown should be fatal, so this is at the server's discretion).
Are you using the same physical machine to test both the in-network and external-network connections? If not, are you sure that the external-network client has the private key accessible?
I have not configured Fiddler client authentication before. Does it read the client certificate and key from the standard certificate stores? Does it read directly from a PKCS12?
One other thing that may be helpful is inspecting the TLS handshake in WireShark. Specifically, check out the Server's "Certificate Request" message, as the data here clues the client (IE9) which client certificates it should display in the prompt. Compare this for the internal and external connections.