Hello
I would like to share a patch that adds a feature to libpq to automatically select the best client certificate to send to the server (if it requests one). This feature is inspired by this email discussion years ago:
https://www.postgresql.org/message-id/200905081539.n48Fdl2Y003286%40no.baka.org. This feature is useful if libpq client needs to communicate with multiple TLS-enabled PostgreSQL servers with different TLS certificate setups. Instead of letting the application to figure out the right certificate for the right server, the patch allows libpq library itself to pick the most ideal client certificate to send to the server.
Currently, we rely on options “sslcert” and “sslkey” parameters on the client side to select a client certificate + private key to send to the server, the patch adds 2 new options. “sslcertdir” and “sslkeydir” to specify directories where all possible certificate and private key files are stored. The new options cannot be used with “sslcert” and “sslkey” at the same time.
The most ideal certificate selection is based on the trusted CA names sent by the server in “Certificate Request” handshake message; obtained by the client making a call to “SSL_get0_peer_CA_list()” function. This list of trusted CA names tells the client the list of “issuers” that this server can trust. Inside “sslcertdir”, If a client certificate candidate’s issuer name equals to one of the trusted CA names, then that is the certificate to use. Once a candidate certificate is identified, the patch will then look for a matching private key in “sslkeydir”. These actions are performed in certificate callback function (cert_cb), which gets called when server requests a client certificate during TLS handshake.
This patch requires OpenSSL version 1.1.1 or later to work. The feature will be disabled with older OpenSSL versions. Attached is a POC patch containing the described feature.
Limitations:
One limitation of this feature is that it does not quite support the case where multiple private key files inside “sslkeydir” are encrypted with different passwords. When the client wants to find a matching private key from “sslkeydir”, it will always use the same password supplied by the client (via “sslpassword” option) to decrypt the private key it tries to access.
Also, no tap tests have been added to the patch to test this feature yet. So, to test this feature, we will need to prepare the environment manually:
1. generate 2 root CA certificates (ca1 and ca2), which sign 2 sets of client and server certificates.
2. configure the server to use a server certificate signed by either ca1 or ca2.
3. put all client certificates and private keys (signed by both ca1 and ca2) into a directory (we will point"sslcertdir" and "sslkeydir" to this directory)
4. based on the root CA certificate configured at the server side, the client will pick the certificate that the server can trust from specified "sslcertdir" and "sslkeydir" directories
Please let me know what you think. Any comments / feedback are greatly appreciated.
Best regards
================
Cary Huang
Highgo Software (Canada)
www.highgo.ca