[PATCH v1] Add ssl_alt_cert_file/ssl_alt_key_file for dual RSA+ECDSA certificate support - Mailing list pgsql-hackers
| From | Renaud Métrich |
|---|---|
| Subject | [PATCH v1] Add ssl_alt_cert_file/ssl_alt_key_file for dual RSA+ECDSA certificate support |
| Date | |
| Msg-id | 0cabf744-6d58-4bc4-817a-413c804cf61d@redhat.com Whole thread |
| Responses |
Re: [PATCH v1] Add ssl_alt_cert_file/ssl_alt_key_file for dual RSA+ECDSA certificate support
|
| List | pgsql-hackers |
Hi hackers, PostgreSQL currently supports only one SSL certificate per server instance (via ssl_cert_file/ssl_key_file). Web servers like httpd, nginx, and haproxy have long supported serving multiple certificates of different key types (e.g., RSA and ECDSA simultaneously), letting OpenSSL select the appropriate one during the TLS handshake based on the negotiated cipher suite. PostgreSQL cannot do this today, and there is no viable workaround — TLS-terminating proxies don't work because PostgreSQL uses an in-protocol SSL upgrade rather than raw TLS connections. This patch adds two new GUC parameters, ssl_alt_cert_file and ssl_alt_key_file, which allow loading an alternate certificate alongside the primary one. OpenSSL natively supports one certificate per key type in a single SSL_CTX; we just need to call SSL_CTX_use_certificate_file() and SSL_CTX_use_PrivateKey_file() a second time for the alternate key type. The main challenge was the SNI architecture introduced in PG 19. The ssl_update_ssl() function copies the certificate from the per-host SSL_CTX to the per-connection SSL object, but the original code calls SSL_CTX_get0_certificate() only once — which returns a single cert — and SSL_use_cert_and_key() with override=1, wiping any additional certs. The fix iterates all certificate types in the SSL_CTX using SSL_CTX_set_current_cert(SSL_CERT_SET_FIRST/NEXT) and loads each onto the SSL object with override=1 for the first and override=0 for subsequent ones. A secondary issue was that be_tls_get_server_cert_types() originally accessed SSL_hosts->default_host->ssl_ctx at query time, but SSL_hosts is allocated in PostmasterContext which child backends delete after InitPostgres(). This caused a segfault. The fix caches the cert types string in a static variable during be_tls_init() while the SSL_CTX is still valid. For observability, the patch adds ssl_server_cert_type() and ssl_server_cert_types() to the sslinfo extension (bumped to v1.3): SELECT ssl_server_cert_type(); -- 'ECDSA' (per-connection) SELECT ssl_server_cert_types(); -- 'RSA, ECDSA' (server-wide) Usage is straightforward: # postgresql.conf ssl = on ssl_cert_file = 'server.crt' # RSA certificate ssl_key_file = 'server.key' ssl_alt_cert_file = 'server-ecdsa.crt' # ECDSA certificate ssl_alt_key_file = 'server-ecdsa.key' Both parameters must be set together; setting one without the other produces a configuration error. When neither is set, behavior is identical to an unpatched server. The patch targets master (currently 19beta1) and is intended for application — it is not WIP. It compiles cleanly, and the full SSL test suite passes without regressions: 443/443 tests (001_ssltests, 002_scram, 003_sslinfo, 004_sni, 004_ssl_alt_cert). The new test 004_ssl_alt_cert.pl covers 20 subtests: basic connectivity, GUC verification, cipher-specific cert selection via openssl s_client, configuration mismatch validation, and the sslinfo observability functions. Testing was done on RHEL 9.8 (x86_64) with OpenSSL 3.5.5. There are no platform-specific items; the patch uses only standard OpenSSL APIs available since OpenSSL 1.1.0. Performance impact is negligible — the only added overhead is one extra SSL_CTX_use_certificate_file()/SSL_CTX_use_PrivateKey_file() call during server startup or SIGHUP reload, and the SSL_CTX_set_current_cert() iteration in ssl_update_ssl() which adds one loop iteration per additional key type (typically just one: ECDSA alongside RSA). The patch includes documentation updates (config.sgml, runtime.sgml, sslinfo.sgml) and regression tests. I chose to use a separate ssl_alt_cert_file/ssl_alt_key_file GUC pair rather than a list-based approach (e.g., ssl_cert_file accepting multiple values) to keep the interface simple and backward-compatible. In practice, the only two key types in widespread use today are RSA and ECDSA — EdDSA (Ed25519/Ed448) server certificates are still not commonly issued by public CAs and have limited client support. A single alternate pair therefore covers the real-world need. Should EdDSA adoption grow in the future, the ssl_update_ssl() fix in this patch already handles an arbitrary number of key types in the SSL_CTX, so extending the interface would be straightforward. The attached patch is: v1-0001-Add-ssl_alt_cert_file-ssl_alt_key_file-for-dual-R.patch 16 files changed, 591 insertions(+), 22 deletions(-) Thanks, Renaud Métrich Red Hat
Attachment
pgsql-hackers by date: