-
Notifications
You must be signed in to change notification settings - Fork 8
fix(ssl): sslmode=prefer does not upgrade to TLS on TLS-capable server #722
Description
Problem
With sslmode=prefer (the default), rpg connects to a TLS-capable server but does not negotiate TLS — ssl=f in pg_stat_ssl.
psql with the same settings connects with TLS enabled (ssl=t).
Repro
# Server has TLS enabled (self-signed cert)
PGPASSWORD=testpass rpg -h localhost -p 15436 -U postgres \
-c "SELECT ssl FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
# => ssl=f
PGPASSWORD=testpass psql -h localhost -p 15436 -U postgres \
-c "SELECT ssl FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
# => ssl=tExpected
sslmode=prefer should attempt TLS first and only fall back to plaintext if TLS is unavailable. rpg appears to fall back to plaintext even when TLS is available.
Context
The self-signed cert causes a rustls verification failure, which rpg treats as "TLS unavailable" and falls back. But psql (OpenSSL) is more permissive — with prefer it accepts self-signed certs without verification (just like require). rpg should do the same: for prefer, use the no-verify TLS config (NoVerifier, same as require), not the webpki roots config.
Fix hint
In connect_one(), the SslMode::Prefer branch calls connect_tls_default() which uses webpki roots. It should use connect_tls_with_config() with make_tls_config_require() (no-verify) — same as sslmode=require. TLS without cert verification is strictly better than no TLS.
Discovered
Full connection matrix audit, 2026-03-24 (Section D).