diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 9d472d2d3d6..eeb6ae79d06 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -8917,7 +8917,7 @@ DO $d$ END; $d$; 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')" 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 diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 3ec458ce09d..52622fe4c1a 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1777,6 +1777,27 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + sslsniServer Name Indication + + + By default, libpq sets the TLS extension Server Name + Indication (SNI) on SSL-enabled connections. See RFC 6066 + for details. By setting this parameter to 0, this is turned off. + + + + 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. + + + + requirepeer @@ -7797,6 +7818,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) + + + + PGSSLSNI + + PGSSLSNI behaves the same as the connection parameter. + + + diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 56a8266bc3f..aa654dd6a8e 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -303,6 +303,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "SSL-Revocation-List-Dir", "", 64, offsetof(struct pg_conn, sslcrldir)}, + {"sslsni", "PGSSLSNI", "1", NULL, + "SSL-SNI", "", 1, + offsetof(struct pg_conn, sslsni)}, + {"requirepeer", "PGREQUIREPEER", NULL, NULL, "Require-Peer", "", 10, offsetof(struct pg_conn, requirepeer)}, @@ -4095,6 +4099,8 @@ freePGconn(PGconn *conn) free(conn->sslcrldir); if (conn->sslcompression) free(conn->sslcompression); + if (conn->sslsni) + free(conn->sslsni); if (conn->requirepeer) free(conn->requirepeer); if (conn->ssl_min_protocol_version) diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 9c2222c1d15..6f357dfbfec 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -1082,6 +1082,28 @@ initialize_SSL(PGconn *conn) SSL_CTX_free(SSL_context); 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 * combination if there is colon present - we don't support files with diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 3f7907127ef..e81dc37906b 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -383,6 +383,7 @@ struct pg_conn char *sslrootcert; /* root certificate filename */ char *sslcrl; /* certificate revocation list filename */ 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 *gssencmode; /* GSS mode (require,prefer,disable) */ char *krbsrvname; /* Kerberos service name */