Re: what can go in root.crt ?

From: Chapman Flack <chap(at)anastigmatix(dot)net>
To: Bruce Momjian <bruce(at)momjian(dot)us>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: what can go in root.crt ?
Date: 2020-05-26 03:17:46
Message-ID: 5ECC8A5A.6080008@anastigmatix.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 05/25/20 22:03, Bruce Momjian wrote:
> Did you review the PG documentation about intermediate certificates?
>
> https://www.postgresql.org/docs/13/ssl-tcp.html#SSL-CERTIFICATE-CREATION

AFAICT, there isn't much in that section to apply to my question.

> Is there a specific question you have?

I'm pretty sure there is. :) Let me try to clarify it.

The doc section you linked has an example showing how to be my own CA,
and generate a chain of certs including a self-signed one to serve as
the root. It suggests putting that self-signed one in root.crt on the
client.

That means the client will happily connect to any server wearing a
certificate signed by that root (or by intermediates that can be followed
up to that root). For the example that's fine, because that root signer
is me, and there aren't a lot of other certs around that chain back to it.

At $work we have Ways Of Doing Things. Generating our own self-signed certs
generally isn't among those. If I want a certificate so I can stand up
a server, I generate a key and a CSR, I send the CSR to our Bureau of
Making Certificates Happen, and they send me back a signed cert with
a chain of external authorities, ending in the self-signed certificate
of a prominent commercial root CA.

Sure, I can put that self-signed root cert into root.crt on the client,
and my client will happily connect to my server.

But in this case the world is teeming with other certificates and even
other whole sub-CAs that chain back to that prominent root issuer.
Granted, you might have to be a bit enterprising to find a sub-CA out
there that will sign a cert for you with the name of my server in it,
but if you can, my client will follow the chain back to that same root,
and therefore trust it.

So I would like to be able to do one of two things:

1. I would like to put my server's end-entity (leaf) certificate
in the root.crt file, and have my client only accept a server
with that exact cert.

Or,

2. I would like to put one of the lower intermediates from the chain
into the root.crt file, to at least limit my client to trusting
only certs signed by that particular sub-CA.

What seems to be happening (for the libpq and libssl versions in 18.04
anyway) is that the certificate that I put in root.crt is found, but
because it isn't a literal "root", as in signer-of-itself, the library
declares a verification failure because it hasn't been able to continue
climbing the chain to find a "root" cert.

Whereas I would like it to say "but I don't have to do that, because
I have already verified as far as this certificate that the administrator
deliberately placed in this file here to tell me to trust it."

In Java, for example, the analogous file is called trustStore, which
may be a better name. You populate the trustStore with certificates you
consider trusted. They can be root certs, intermediate certs, or flat-out
leaf certs of individual servers. Whenever Java is verifying a connection,
as soon as its chain-following brings it to a cert that you placed in
the trustStore, it stops and says "yes, I trust this, because you have
told me to."

I have also encountered web browsers that work in both of these ways.
The last time I was standing up a temporary web service to test something,
I did make a self-signed cert and then use it to sign a leaf cert for
the service. I was testing with Chrome and Firefox and they both have
spiffy UIs for managing a list of trusted certs, but one of them (I have
forgotten which) allowed me to simply load the leaf cert that I wanted
to trust, while the other insisted I give it the self-signed root that
I had signed the leaf cert with.

I think the former behavior, which is like Java's, is strictly more useful.

What puzzled me today, and why I began this thread, is that I hadn't
(and still haven't) found a clear discussion in the doc of these two
approaches and which one libpq is intended to supply. I know that my
attempts to use root.crt like a trustStore have so far been met with
failure, but between the terse error message and the sparse doc, it is
hard to know whether that's a "you can't do that, dummy!" or a "you
just haven't guessed the right way yet."

If there is a way to get a trustStore-like behavior and have the client
trust an intermediate or leaf cert that I explicitly tell it to, but I
just haven't pronounced the magic words right, this email may be read
as "oh good, how do I do it?"

If the current implementation really is stuck accepting only self-signed
certs in that file and therefore can't offer trustStore-like behavior,
this email may be read as "it could be made more useful by changing that."

And in either case, there seems to be room in the docs for some
discussion of the difference between those two models and which one
libpq is meant to offer.

I would not be unwilling to try my hand at such a doc patch one day,
but for now I'm still hoping to learn the answers myself.

Regards,
-Chap

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Laurenz Albe 2020-05-26 03:22:13 Re: what can go in root.crt ?
Previous Message Laurenz Albe 2020-05-26 03:17:22 Re: Default gucs for EXPLAIN