Commit 5c55dc8b authored by Peter Eisentraut's avatar Peter Eisentraut

libpq: Set Server Name Indication (SNI) for SSL connections

By default, have libpq set the TLS extension "Server Name Indication" (SNI).

This allows an SNI-aware SSL proxy to route connections.  (This
requires a proxy that is aware of the PostgreSQL protocol, not just
any SSL proxy.)

In the future, this could also allow the server to use different SSL
certificates for different host specifications.  (That would require
new server functionality.  This would be the client-side functionality
for that.)

Since SNI makes the host name appear in cleartext in the network
traffic, this might be undesirable in some cases.  Therefore, also add
a libpq connection option "sslsni" to turn it off.

Discussion: https://www.postgresql.org/message-id/flat/7289d5eb-62a5-a732-c3b9-438cee2cb709%40enterprisedb.com
parent c1968426
...@@ -8917,7 +8917,7 @@ DO $d$ ...@@ -8917,7 +8917,7 @@ DO $d$
END; END;
$d$; $d$;
ERROR: invalid option "password" ERROR: invalid option "password"
HINT: Valid options in this context are: service, passfile, channel_binding, connect_timeout, dbname, host, hostaddr, port, options, application_name, keepalives, keepalives_idle, keepalives_interval, keepalives_count, tcp_user_timeout, sslmode, sslcompression, sslcert, sslkey, sslrootcert, sslcrl, sslcrldir, requirepeer, ssl_min_protocol_version, ssl_max_protocol_version, gssencmode, krbsrvname, gsslib, target_session_attrs, use_remote_estimate, fdw_startup_cost, fdw_tuple_cost, extensions, updatable, fetch_size, batch_size, async_capable, keep_connections HINT: Valid options in this context are: service, passfile, channel_binding, connect_timeout, dbname, host, hostaddr, port, options, application_name, keepalives, keepalives_idle, keepalives_interval, keepalives_count, tcp_user_timeout, sslmode, sslcompression, sslcert, sslkey, sslrootcert, sslcrl, sslcrldir, sslsni, requirepeer, ssl_min_protocol_version, ssl_max_protocol_version, gssencmode, krbsrvname, gsslib, target_session_attrs, use_remote_estimate, fdw_startup_cost, fdw_tuple_cost, extensions, updatable, fetch_size, batch_size, async_capable, keep_connections
CONTEXT: SQL statement "ALTER SERVER loopback_nopw OPTIONS (ADD password 'dummypw')" CONTEXT: SQL statement "ALTER SERVER loopback_nopw OPTIONS (ADD password 'dummypw')"
PL/pgSQL function inline_code_block line 3 at EXECUTE PL/pgSQL function inline_code_block line 3 at EXECUTE
-- If we add a password for our user mapping instead, we should get a different -- If we add a password for our user mapping instead, we should get a different
......
...@@ -1777,6 +1777,27 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname ...@@ -1777,6 +1777,27 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="libpq-connect-sslsni" xreflabel="sslsni">
<term><literal>sslsni</literal><indexterm><primary>Server Name Indication</primary></indexterm></term>
<listitem>
<para>
By default, libpq sets the TLS extension <quote>Server Name
Indication</quote> (SNI) on SSL-enabled connections. See <ulink
url="https://tools.ietf.org/html/rfc6066#section-3">RFC 6066</ulink>
for details. By setting this parameter to 0, this is turned off.
</para>
<para>
The Server Name Indication can be used by SSL-aware proxies to route
connections without having to decrypt the SSL stream. (Note that this
requires a proxy that is aware of the PostgreSQL protocol handshake,
not just any SSL proxy.) However, SNI makes the destination host name
appear in cleartext in the network traffic, so it might be undesirable
in some cases.
</para>
</listitem>
</varlistentry>
<varlistentry id="libpq-connect-requirepeer" xreflabel="requirepeer"> <varlistentry id="libpq-connect-requirepeer" xreflabel="requirepeer">
<term><literal>requirepeer</literal></term> <term><literal>requirepeer</literal></term>
<listitem> <listitem>
...@@ -7797,6 +7818,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) ...@@ -7797,6 +7818,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<indexterm>
<primary><envar>PGSSLSNI</envar></primary>
</indexterm>
<envar>PGSSLSNI</envar> behaves the same as the <xref
linkend="libpq-connect-sslsni"/> connection parameter.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<indexterm> <indexterm>
......
...@@ -303,6 +303,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { ...@@ -303,6 +303,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"SSL-Revocation-List-Dir", "", 64, "SSL-Revocation-List-Dir", "", 64,
offsetof(struct pg_conn, sslcrldir)}, offsetof(struct pg_conn, sslcrldir)},
{"sslsni", "PGSSLSNI", "1", NULL,
"SSL-SNI", "", 1,
offsetof(struct pg_conn, sslsni)},
{"requirepeer", "PGREQUIREPEER", NULL, NULL, {"requirepeer", "PGREQUIREPEER", NULL, NULL,
"Require-Peer", "", 10, "Require-Peer", "", 10,
offsetof(struct pg_conn, requirepeer)}, offsetof(struct pg_conn, requirepeer)},
...@@ -4095,6 +4099,8 @@ freePGconn(PGconn *conn) ...@@ -4095,6 +4099,8 @@ freePGconn(PGconn *conn)
free(conn->sslcrldir); free(conn->sslcrldir);
if (conn->sslcompression) if (conn->sslcompression)
free(conn->sslcompression); free(conn->sslcompression);
if (conn->sslsni)
free(conn->sslsni);
if (conn->requirepeer) if (conn->requirepeer)
free(conn->requirepeer); free(conn->requirepeer);
if (conn->ssl_min_protocol_version) if (conn->ssl_min_protocol_version)
......
...@@ -1082,6 +1082,28 @@ initialize_SSL(PGconn *conn) ...@@ -1082,6 +1082,28 @@ initialize_SSL(PGconn *conn)
SSL_CTX_free(SSL_context); SSL_CTX_free(SSL_context);
SSL_context = NULL; SSL_context = NULL;
/*
* Set Server Name Indication (SNI), if enabled by connection parameters.
* Per RFC 6066, do not set it if the host is a literal IP address (IPv4
* or IPv6).
*/
if (conn->sslsni && conn->sslsni[0] &&
!(strspn(conn->pghost, "0123456789.") == strlen(conn->pghost) ||
strchr(conn->pghost, ':')))
{
if (SSL_set_tlsext_host_name(conn->ssl, conn->pghost) != 1)
{
char *err = SSLerrmessage(ERR_get_error());
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set SSL Server Name Indication (SNI): %s\n"),
err);
SSLerrfree(err);
SSL_CTX_free(SSL_context);
return -1;
}
}
/* /*
* Read the SSL key. If a key is specified, treat it as an engine:key * Read the SSL key. If a key is specified, treat it as an engine:key
* combination if there is colon present - we don't support files with * combination if there is colon present - we don't support files with
......
...@@ -383,6 +383,7 @@ struct pg_conn ...@@ -383,6 +383,7 @@ struct pg_conn
char *sslrootcert; /* root certificate filename */ char *sslrootcert; /* root certificate filename */
char *sslcrl; /* certificate revocation list filename */ char *sslcrl; /* certificate revocation list filename */
char *sslcrldir; /* certificate revocation list directory name */ char *sslcrldir; /* certificate revocation list directory name */
char *sslsni; /* use SSL SNI extension (0 or 1) */
char *requirepeer; /* required peer credentials for local sockets */ char *requirepeer; /* required peer credentials for local sockets */
char *gssencmode; /* GSS mode (require,prefer,disable) */ char *gssencmode; /* GSS mode (require,prefer,disable) */
char *krbsrvname; /* Kerberos service name */ char *krbsrvname; /* Kerberos service name */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment