Score:4

Is it possible to get a browser to present a client side certificate even if the client cert isn't signed by the same CA as the server cert?

mx flag

I'm in a strange scenario where I have a server with NodeJS backend and ReactJS frontend that does record keeping where the customer wants to use user certificates to ID who visits this internal site. The problem is they have a very large network, with convoluted PKI, and the public cert I have been given to assign to the site doesn't necessarily match all the clients that could visit it.

I have nginx up front with the ssl_verify_client optional_no_ca; set but I noticed that browsers will only give users the option of selecting their client certificate if they have a certificate that is properly signed by the same CA as the public key presented by nginx.

My understanding is that during the certificate request the server can specify what CAs are acceptable. It seems like nginx may be doing this but I’m not sure that’s the case. My plan is start dissecting with wireshark tomorrow. Is there a known way to get my site to ask browsers to always prompt users for a client certificate? Have I perhaps misunderstood something along the way?

anx avatar
fr flag
anx
As I have just written [over here](https://security.stackexchange.com/a/271568/247960) client authentication of the properly transport integrated fashion is not something a great many involved parties care for. Carefully consider whether what you are setting up would instead be better served by an industry with significant cash flow, such as selling pennies worth of smartcards at double digit dollars. `FIDO2` enjoys fairly reasonable software support by now. When something on your premise makes decision on an individual key level anyway, you may not want that TLS signature chain stuff at all.
Grant Curell avatar
mx flag
@anx the users do have smart cards - that's what I'm pulling the client certificates from. I don't actually need authentication - I just need their names. Note: this is all happening on an internal network - nothing is internet facing. The customer just wants usage statistics. Are you saying there is a better way to accomplish that? Edit: Maybe worth mentioning is that I'm a third party here and none of the above parameters are within my control or even within the control of the portion of the customer for whom I'm writing the code.
anx avatar
fr flag
anx
I am just surprised that no other "identify me via foobar SSO solution please" button is considered well before client certificates. Why would your app not sit one some subdomain that has readable user identifiers ready for direct consumption in its cookies (those in turn set as a result of stronger authentication), or add a button to set such cookie via redirects through whatever SSO webapp they are betting their security on, without caring one bit about client certificate chains?
Grant Curell avatar
mx flag
And you would be absolutely right to be surprised . I did ask about doing something like SSPI but the problem is not everything is actually on the same AD domain. It's just a mess of mushed together system built over decades. I just found out they *should* all have the same root certificate, but things got messed up so at least that should be fixable. I am open to other suggestions but AFAIK the only thing I can count on is that they should all be signed with this one root CA I am now going to get
Score:5
fr flag
anx

Simple: Put into your nginx configuration what authorities certificates you want nginx to request. Nginx will send & verify those depending on your ssl_verify_client setting. Thats it.

ssl_client_certificate = /path/to/concatenated-x509.pem
# contents of /path/to/concatenated-x509.pem may contains, possibly many:
# -----BEGIN CERTIFICATE---- much foo bar -----END CERTIFICATE-----

The two directions of authenticating via certificates are unrelated. Your server does present a certificate, and there is no rule that says there cannot be any overlap, but otherwise, you may ask for whatever authority you want. Nginx does not even send the public key of the certificates your configure to be "sent" using the ssl_client_certificate. It sends a list of acceptable signature algorithms, and a list of the distinguished name sets of those certificates: something like /C=DK/O=ACME Inc./CN=ACME CA3.

EDIT: note other answer - NOT requesting any CA in particular is an option, too.

You may run into interoperability problems if you have to support older (pre-TLSv1.3) clients together with mixed signature algorithms (mix between EC and RSA), and if your list of distinguished names becomes excessively large. Try what works, specifically using the software that you need to support, and see to it that error messages are either self-explanatory or properly documented for whatever customers or business partners might encounter them.


‡) Thats it for getting a fully TLSv1.3-supporting client to present a certificate signed by any CA on your list. You are not done, then. Please have very little trust in assuming that everything signed by any of not-managed-by-you CAs is the authorized user the certificate suggests it is, and ensure very strict validation in your application behind the nginx proxy that actually deal with those optionally presented, possibly worthless/irrelevant certificates.

Grant Curell avatar
mx flag
"Simple: Put into your nginx configuration what authorities certificates you want nginx to request. Thats it‡." I feel silly asking this... but where does that go? I haven't been able to find that option but it sounds like that's exactly what I'm looking for
anx avatar
fr flag
anx
@GrantCurell Its just another PEM file. Copy the issuer certificates you care about into a single file, and point nignx there. I have never bothered to try what happens if you put 65536 different CAs there, but I guess if your "convoluted PKI" use case is well below that limit, clients will figure something out.
Grant Curell avatar
mx flag
Ok, that's what I thought - I wasn't sure if I could just list the DNs somewhere but it seems like I have to actually have the CA certs for any of the potential clients (I was hoping to avoid that part but that's the bit I kind of figured would work that way). Thanks for the help!
anx avatar
fr flag
anx
@GrantCurell Well you *are* just listing the DNs .. in a format most easily produced by concatenating the certificates. Nginx likes to read them in the context of some x509 fluff, eliminating needless repetition (and a footgun) in case you want .. you know, that thing the option is primarily meant for.
Grant Curell avatar
mx flag
Heads up - this answer appears to be incorrect. I have added my own answer below, if I'm off the mark definitely let me know and I'll reverse course.
Ginnungagap avatar
gu flag
For future reference, nginx.org/r/<directive> will get you straight to the documentation for that directive, eg. [nginx.org/r/ssl_client_certificate](https://nginx.org/r/ssl_client_certificate)
Score:2
mx flag

I want to sincerely thank @anx for his answer as it actually got me moving down the right path however it appears to be incorrect.

anx pointed me correctly to the docs

The docs say this about ssl_client_certificate:

Specifies a file with trusted CA certificates in the PEM format used to verify client certificates and OCSP responses if ssl_stapling is enabled. The list of certificates will be sent to clients. If this is not desired, the ssl_trusted_certificate directive can be used.

The reason we aren't getting the prompt is that nginx is sending a list of the CA certs to the browser and the browser looks at that. If the browser sees it doesn't have a client cert (with private key) matching that CA, it will not show the prompt.

As the docs say ssl_trusted_certificate however, does not send the list.

Specifies a file with trusted CA certificates in the PEM format used to verify client certificates and OCSP responses if ssl_stapling is enabled. In contrast to the certificate set by ssl_client_certificate, the list of these certificates will not be sent to clients.

I just finished testing it both ways; ssl_client_certificate causes browsers lacking matching certificates to not prompt whereas ssl_trusted_certificate does exactly what we want; it does not send a list of CA certs and always prompts.

On a usability note to anyone else who has to test this, you have to close and re-open the browser to get the prompt to show. A page refresh is insufficient.

anx avatar
fr flag
anx
If not sending the DN filter at all works for the clients you care about (meaning: you are getting the certificates and intermediates you care about, and not just something unrelated that happened to be the first possibility - do test with the actual software versions), it might be better for your purpose for another reason on top of not needing to enumerate all possible CAs: Clients may attach extraneous CA certificates they would otherwise not send along as they assume you have them, potentially revealing something you previously did not have.
Grant Curell avatar
mx flag
In retrospect, what I should have put in the OP is, "The only thing that matters is capturing the client's CN for stats tracking/compliance purposes. This is not an authentication mechanism"
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.