Is it possible to automatically select correct client side certificate? - ssl

I have configured an Apache httpd website with SSL client side certificates so that only users who have installed the correct certificate in their web browsers can access the website.
If there is only one client side certificate installed the web browser will automatically select it (it is not the default, but it can be configured somewhere in the settings dialog). But if a user has more than one certificate installed, the web browser presents a list of certificates and the user has to pick the right one to continue.
The question is: Is there a way to configure httpd to send a hint so that the web browser can automatically select the required certificate?

The SSL (TLS) protocol only allows the server to specify two constraints on the client certificate:
The type of certificate (RSA, DSA, etc.)
The trusted certificate authorities (CAs) that signed the client certificate
You can use "openssl s_client" to see which CAs your Apache server trusts for client certs. I do not know how to configure Apache to change that list (sorry), but I bet there is a way. So if you can limit the list to (say) your own organization's CA alone, then you will have done all you can to allow a Web browser to select the client cert automatically.
As Eugene said, whether the browser actually does so is up to the particular browser.

I'd say that as selection of the certificate is a client-side task, there's no definite way to force the client use this or that certificate from the server side.

In addition to what #Nemo and #Eugene said, by default, Apache Httpd will send the list of CAs it gets from its SSLCACertificateFile or SSLCACertificatePath configuration directives.
However, you can force it to send a different list in certificate_authorities using the SSLCADNRequestFile or SSLCADNRequestPath directives and pointing them to another set of certificates. Only the Subject DN of these certificates is used (and send in the list). If you want to force certain names, you can even self-sign these certificates with whichever name you want. I've tried this (in conjunction with SSLVerifyClient optional_no_ca, and you can get clients to send certificates for CA certificates that the server doesn't actually have. (This isn't necessarily useful, but it works.)

Related

How to enforce tomcat server not to share SSL public certificate to clients(Browsers) requesting for it?

A Certified Domain should be accessible only if SSL public certificate of the domain is already present in client's trust store. If not, client should prompt to import server certificate instead of getting it from tomcat server automatically(Via SSL handshake)
This will not work: the server has no knowledge which CA certificates are known to the client so the server cannot decide what to send to the client. Also, the server can only send a certificate to the client but not make the client import a new root CA - no matter if with or without prompt.
Apart from that it makes no sense: the idea of TLS/HTTPS is that the client will only connect to a server which identity can be verified. If the server can make a client import a new trusted root CA an attacker could do the same and thusman in the middle attacks would be possible.
If one instead just want to know if the client will trust a specific certificate or not one could include a resource (image, script...) served with this certificate into a known good HTML page and then check with some script in the page if the resource was loaded successfully. This check could also result in a redirect of the client, for example to some page describing the problem and linking to the correct root CA.

Using letsencrypt to sign SSL certificates for local servers

Can I use a certificate from letsencrypt to sign local certificates?
I'm annoyed when accessing routers and APs at 192.168.x.x to get security warnings.
I could create my own root cert, and import it into all my browsers etc, and create certs for all the local servers.
But I'd rather have the chain device -> www.example.com -> letsencrypt -> root
Then also guests could use my local servers/services without this security error.
No, you can not because the certificate issued to you by letsencrypt will not have the keyusage certificate signing enabled. Without this attribute in the issuer, any browser or SSL client musth reject the certificate.
If this were possible, anyone could issue valid certificates for any server simply by having a valid certificate from a trusted CA
If you want to issue certificates for your local servers you will need to create your own CA and include the root certificate in the truststore of each client
Yes, you can... but not like that
Yes, you can get certificates for servers on a private network. The domain must be a real domain with public txt records, but the A, AAAA, and CNAME records can be private/non-routable (or in a private zone).
No, the way to do that isn't by using Let's Encrypt certificates to sign local certificates.
You can accomplish exactly what you want to accomplish using the DNS-01 challenge (setting txt records for your domain).
Who is your domain / dns provider?
Immediate, but Temporary Solution
If you want to test it out real quick, try https://greenlock.domains and choose DNS instead of HTTP for the "how do you want to do this" step.
Automatable Integration
If you want a configurable, automatable, deployable solution try greenlock.js (there are node plugins for Cloudflare, Route 53, Digital Ocean, and a few other DNS providers).
Both use Let's Encrypt under the hood. Certbot can also be used for either case and can use python plugins.
Possibly related...
P.S. You might also be interested in a service like Telebit, localtunnel, or ngrok.

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.

HAProxy dynamic SSL configuration for multiple domains

I have something like 100 similar websites in two VPS. I would like to use HAProxy to switch traffic dynamically but at the same time I would like to add an SSL certificate.
I want to use add a variable to call the specific certificate for each website.
For example:
frontend web-https
bind 0.0.0.0:443 ssl crt /etc/ssl/certs/{{domain}}.pem
reqadd X-Forwarded-Proto:\ https
rspadd Strict-Transport-Security:\ max-age=31536000
default_backend website
I'd like also check if the SSL certificate is really available and in case it is not available then switch to HTTP with a redirect.
Is this possibile with HAProxy?
This can be done, but TLS (SSL) does not allow you to do it the way you envision.
First, HAProxy allows you to specify a default certificate and a directory for additonal certificates.
From the documentation for the crt keyword
If a directory name is used instead of a PEM file, then all files found in
that directory will be loaded in alphabetic order unless their name ends with
'.issuer', '.ocsp' or '.sctl' (reserved extensions). This directive may be
specified multiple times in order to load certificates from multiple files or
directories. The certificates will be presented to clients who provide a
valid TLS Server Name Indication field matching one of their CN or alt
subjects. Wildcards are supported, where a wildcard character '*' is used
instead of the first hostname component (eg: *.example.org matches
www.example.org but not www.sub.example.org).
If no SNI is provided by the client or if the SSL library does not support
TLS extensions, or if the client provides an SNI hostname which does not
match any certificate, then the first loaded certificate will be presented.
This means that when loading certificates from a directory, it is highly
recommended to load the default one first as a file or to ensure that it will
always be the first one in the directory.
So, all you need is a directory containing each cert/chain/key in a pem file, and a modification to your configuration like this:
bind 0.0.0.0:443 ssl crt /etc/haproxy/my-default.pem crt /etc/haproxy/my-cert-directory
Note you should also add no-sslv3.
I want to use add a variable to call te specific certificate for each website
As noted in the documentation, if the browser sends Server Name Identification (SNI), then HAProxy will automatically negotiate with the browser using the appropriate certificate.
So configurable cert selection isn't necessary, but more importantly, it isn't possible. SSL/TLS doesn't work that way (anywhere). Until the browser successfully negotiates the secure channel, you don't know what web site the browser will be asking for, because the browser hasn't yet sent the request.
If the browser doesn't speak SNI -- a concern that should be almost entirely irrelevant any more -- or if there is no cert on file that matches the hostname presented in the SNI -- then the default certificate is used for negotiation with the browser.
I'd like also check if the ssl is real available and in case is not available switch to http with a redirect
This is also not possible. Remember, encryption is negotiated first, and only then is the HTTP request sent by the browser.
So, a user will never see your redirect unless they bypass the browser's security warning -- which they must necessarily see, because the hostname in the default certificate won't match the hostname the browser expects to see in the cert.
At this point, there's little point in forcing them back to http, because by bypassing the browser security warning, they have established a connection that is -- simultaneously -- untrusted yet still encrypted. The connection is technically secure but the user has a red × in the address bar because the browser correctly believes that the certificate is invalid (due to the hostname mismatch). But on the user's insistence at bypassing the warning, the browser still uses the invalid certificate to establish the secure channel.
If you really want to redirect even after all of this, you'll need to take a look at the layer 5 fetches. You'll need to verify that the Host header matches the SNI or the default cert, and if your certs are wildcards, you'll need to accommodate that too, but this will still only happen after the user bypasses the security warning.
Imagine if things were so simple that a web server without a valid certificate could hijack traffic by simply redirecting it without the browser requiring the server's certificate being valid (or deliberate action by the user to bypass the warning) and it should become apparent why your original idea not only will not work, but in fact should not work.
Note also that the certificates loaded from the configured directory are all loaded at startup. If you need HAProxy to discover new ones or discard old ones, you need a hot restart of HAProxy (usually sudo service haproxy reload).

Apache configuration to use different certificates for different Locators on same server

For client authentication, my requirement is to use different certificates for different locator URLs on same IP.
For example:
When a client connects to https://a.b.c.d/locatorA, i want to authenticate the client against certificate A, signed by CA X,
And if a client connects to https://a.b.c.d/locatorB, i want to authenticate the client against certificate B, signed by CA Y.
Also any other URL on a.b.c.d, the client authentication is not needed.
To enable client verification on locatorA and locatorB, I am setting SSLVerifyClient to true in locator directive. And by default SSLVerifyClient is set as none.
But the problem i am facing is how to specify to use Certificate A for locatorA and certificate B for locatorB. I tried adding SSLCertificateFile in locator directives for locatorA and locatorB, but apache said configuration error.
Is there a way i can have different certificates for different URLs on same server based on type of URL?
Thanks,
Kowsik
kowsik.tulabandual#gmail.com
It is not possible to directly map different certificates to URLs under the same host.
Usually, you are restricted to 1 certificate per IP. If you implemented SNI, you could additionally map different certificates to host names under the same IP. For example, you could map Certificate A to host locatorA.example.com.
If that helps, you could additionally redirect http://a.b.c.d/locatorA and/or https://a.b.c.d/locatorA (secured by a common Certificate X) to https://locatorA.example.com/locatorA (secured by Certificate A).
Note that, some older clients do not support SNI.