SSL/TLS Negotiation: Research and Design Decision #76
Replies: 3 comments 1 reply
-
|
Lori tracking issue for TLS upgrade support: ponylang/lori#170 |
Beta Was this translation helpful? Give feedback.
-
SSL/TLS Negotiation: Implementation DesignImplementation plan for adding SSL/TLS negotiation to the postgres driver, building on the Prerequisite: a lori release containing Scope BoundariesIn scope:
Out of scope (future work):
Public API ChangesNew types (new file:
|
Beta Was this translation helpful? Give feedback.
-
|
Implemented in #79 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Research and design decision for adding SSL/TLS negotiation to the ponylang/postgres driver (item 1 from the feature roadmap).
PostgreSQL SSL Negotiation Protocol
PostgreSQL uses a STARTTLS-style negotiation that happens before the StartupMessage:
Int32(8) | Int32(80877103)S(proceed with TLS) orN(no SSL)S: client performs a TLS handshake on the existing TCP socketThe SSLRequest code (
80877103=1234 << 16 | 5679) is intentionally distinct from any valid protocol version number. The server's response is a raw byte, not a standard protocol message.sslmode Behaviors
disableprefer(default)requireverify-caverify-fullPostgreSQL 17+ Direct SSL
PostgreSQL 17 added
sslnegotiation=direct, where the client starts TLS immediately (no SSLRequest round-trip). This requires ALPN extension with protocol name"postgresql". Only works withsslmode=requireor higher.Security Considerations
S, a MITM could inject bytes before the TLS handshake. The client must read exactly one byte, not buffer additional data.E(ErrorResponse) to SSLRequest, the server is unauthenticated — the client must not trust or display the error content.Current Driver Architecture
The connection flow in
session.pony:SSL negotiation needs to be inserted between
on_connected()and sending the StartupMessage.Approaches Considered
Option 1: Modify lori to support TLS upgrade (chosen)
Add a
start_tls(sslctx)method to lori'sTCPConnectionthat initiates a TLS handshake on an existing plain TCP connection. The postgres driver would:TCPConnection.client()S: callconnection.start_tls(sslctx)— lori handles the handshakeN: either send StartupMessage in plaintext or abort, depending on sslmodePros:
_ssl_flush_sends,_ssl_poll, etc.) — this just allows initializing them post-connectionCons:
Option 2: Manual SSL layer in the postgres driver (rejected)
Use lori for plain TCP, but handle TLS ourselves using the
SSLclass directly — intercept all reads/writes to encrypt/decrypt manually.Rejected because: Duplicates what lori already does internally. Error-prone. Mixes transport concerns into the postgres driver.
Option 3: Direct SSL only via
ssl_client()(rejected)Use lori's existing
TCPConnection.ssl_client()which starts TLS immediately.Rejected because: Only works with PostgreSQL 17+ servers configured for direct SSL. Incompatible with the vast majority of PostgreSQL deployments. The integration test environment uses PostgreSQL 14.5.
Decision
Going with Option 1 — modify lori to support TLS upgrade. It's the correct, most maintainable path forward. TLS is a transport concern that belongs in the networking library, and the STARTTLS pattern is common across many protocols.
Tracking issue: ponylang/lori#170
Beta Was this translation helpful? Give feedback.
All reactions