3a0e385048
Currently, debugging client certificate verification failures is mostly limited to looking at the TLS alert code on the client side. For simple deployments, sometimes it's enough to see "sslv3 alert certificate revoked" and know exactly what needs to be fixed, but if you add any more complexity (multiple CA layers, misconfigured CA certificates, etc.), trying to debug what happened based on the TLS alert alone can be an exercise in frustration. Luckily, the server has more information about exactly what failed in the chain, and we already have the requisite callback implemented as a stub. We fill that in, collect the data, and pass the constructed error message back to the main code via a static variable. This lets us add our error details directly to the final "could not accept SSL connection" log message, as opposed to issuing intermediate LOGs. It ends up looking like LOG: connection received: host=localhost port=43112 LOG: could not accept SSL connection: certificate verify failed DETAIL: Client certificate verification failed at depth 1: unable to get local issuer certificate. Failed certificate data (unverified): subject "/CN=Test CA for PostgreSQL SSL regression test client certs", serial number 2315134995201656577, issuer "/CN=Test root CA for PostgreSQL SSL regression test suite". The length of the Subject and Issuer strings is limited to prevent malicious client certs from spamming the logs. In case the truncation makes things ambiguous, the certificate's serial number is also logged. Author: Jacob Champion <pchampion@vmware.com> Discussion: https://www.postgresql.org/message-id/flat/d13c4a5787c2a3f83705124f0391e0738c796751.camel@vmware.com |
||
---|---|---|
.. | ||
Makefile | ||
README.SSL | ||
auth-sasl.c | ||
auth-scram.c | ||
auth.c | ||
be-fsstubs.c | ||
be-gssapi-common.c | ||
be-secure-common.c | ||
be-secure-gssapi.c | ||
be-secure-openssl.c | ||
be-secure.c | ||
crypt.c | ||
hba.c | ||
ifaddr.c | ||
pg_hba.conf.sample | ||
pg_ident.conf.sample | ||
pqcomm.c | ||
pqformat.c | ||
pqmq.c | ||
pqsignal.c |
README.SSL
src/backend/libpq/README.SSL SSL === >From the servers perspective: Receives StartupPacket | | (Is SSL_NEGOTIATE_CODE?) ----------- Normal startup | No | | Yes | | (Server compiled with USE_SSL?) ------- Send 'N' | No | | | | Yes Normal startup | | Send 'S' | | Establish SSL | | Normal startup >From the clients perspective (v6.6 client _with_ SSL): Connect | | Send packet with SSL_NEGOTIATE_CODE | | Receive single char ------- 'S' -------- Establish SSL | | | '<else>' | | Normal startup | | Is it 'E' for error ------------------- Retry connection | Yes without SSL | No | Is it 'N' for normal ------------------- Normal startup | Yes | Fail with unknown --------------------------------------------------------------------------- Ephemeral DH ============ Since the server static private key ($DataDir/server.key) will normally be stored unencrypted so that the database backend can restart automatically, it is important that we select an algorithm that continues to provide confidentiality even if the attacker has the server's private key. Ephemeral DH (EDH) keys provide this and more (Perfect Forward Secrecy aka PFS). N.B., the static private key should still be protected to the largest extent possible, to minimize the risk of impersonations. Another benefit of EDH is that it allows the backend and clients to use DSA keys. DSA keys can only provide digital signatures, not encryption, and are often acceptable in jurisdictions where RSA keys are unacceptable. The downside to EDH is that it makes it impossible to use ssldump(1) if there's a problem establishing an SSL session. In this case you'll need to temporarily disable EDH (see initialize_dh()).