pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feed From: Jeff Davis <pgsql@j-davis.com>
To: Michael Paquier <michael@paquier.xyz>
To: Jonathan S. Katz <jkatz@postgresql.org>
Cc: Stephen Frost <sfrost@snowman.net>
Cc: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
Cc: pgsql-hackers@postgresql.org
Subject: Re: Add "password_protocol" connection parameter to libpq
Date: Tue, 20 Aug 2019 19:09:25 -0700
Message-ID: <4863222980d349a6251065ea67f00ac41dedb162.camel@j-davis.com> (raw )
In-Reply-To: <20190819055100.GC18166@paquier.xyz >
References: <7a7a2f07-d013-eb80-85ba-9edaaf845038@2ndquadrant.com >
<95b40ddcb3897772f075e6891521ee3f06f443d1.camel@j-davis.com >
<93653d2b-7cf7-6992-7d3e-600ffd461354@2ndquadrant.com >
<20190813025634.GF2551@paquier.xyz >
<67726b008fa31d00d9a38257b3d1673b8afff2dd.camel@j-davis.com >
<1e34ce7a-9d4c-dd99-3781-e0a3203f5aef@postgresql.org >
<20190814023857.GB14446@paquier.xyz >
<54269124d50791eacb71f1fead40422185ae8ddc.camel@j-davis.com >
<20190816012815.GW16436@tamriel.snowman.net >
<edaeee0d-5367-ad46-6a5a-1357ea595151@postgresql.org >
<20190819055100.GC18166@paquier.xyz >
On Mon, 2019-08-19 at 14:51 +0900, Michael Paquier wrote:
> On Fri, Aug 16, 2019 at 02:11:57PM -0400, Jonathan S. Katz wrote:
> > To be pedantic, +1 on the channel_binding param.
>
> Seems like we are moving in this direction then. I don't object to
> the introduction of this parameter.
OK, new patch attached. Seems like everyone is in agreement that we
need a channel_binding param.
Regards,
Jeff Davis
Attachments:
[text/x-patch] 0001-Add-libpq-parameter-channel_binding.patch (7.1K, ../4863222980d349a6251065ea67f00ac41dedb162.camel@j-davis.com/2-0001-Add-libpq-parameter-channel_binding.patch)
download | inline diff:
From 0eb8e76d08a64979c3070761efab95d61c4ff887 Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Tue, 20 Aug 2019 18:59:23 -0700
Subject: [PATCH] Add libpq parameter 'channel_binding'.
Allow clients to require channel binding to enhance security against
untrusted servers.
Author: Jeff Davis
Discussion: https://postgr.es/m/227015d8417f2b4fef03f8966dbfa5cbcc4f44da.camel%40j-davis.com
---
doc/src/sgml/libpq.sgml | 19 +++++++++++++++++++
src/interfaces/libpq/fe-auth.c | 30 +++++++++++++++++++++++++++++-
src/interfaces/libpq/fe-connect.c | 28 ++++++++++++++++++++++++++++
src/interfaces/libpq/libpq-int.h | 2 ++
4 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index e7295abda28..1785cb1bcc5 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1118,6 +1118,25 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
</listitem>
</varlistentry>
+ <varlistentry id="libpq-connect-channel-binding" xreflabel="channel_binding">
+ <term><literal>channel_binding</literal></term>
+ <listitem>
+ <para>
+ A setting of <literal>require</literal> means that the connection must
+ employ channel binding; and that the client will not respond to
+ requests from the server for cleartext password or MD5
+ authentication. The default setting is <literal>prefer</literal>,
+ which employs channel binding if available.
+ </para>
+ <para>
+ Channel binding is a method for the server to authenticate itself to
+ the client. It is only supported over SSL connections
+ with <productname>PostgreSQL</productname> 11.0 or later servers using
+ the <literal>scram-sha-256</literal> authentication method.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-connect-connect-timeout" xreflabel="connect_timeout">
<term><literal>connect_timeout</literal></term>
<listitem>
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index ab227421b3b..5df30913337 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -423,6 +423,13 @@ pg_SASL_init(PGconn *conn, int payloadlen)
initPQExpBuffer(&mechanism_buf);
+ if (conn->channel_binding[0] == 'r' && !conn->ssl_in_use)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("Channel binding required, but SSL not in use\n"));
+ goto error;
+ }
+
if (conn->sasl_state)
{
printfPQExpBuffer(&conn->errorMessage,
@@ -488,7 +495,8 @@ pg_SASL_init(PGconn *conn, int payloadlen)
goto error;
}
}
- else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 &&
+ else if (conn->channel_binding[0] != 'r' &&
+ strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 &&
!selected_mechanism)
selected_mechanism = SCRAM_SHA_256_NAME;
}
@@ -565,6 +573,9 @@ pg_SASL_init(PGconn *conn, int payloadlen)
if (initialresponse)
free(initialresponse);
+ if (strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
+ conn->channel_bound = true;
+
return STATUS_OK;
error:
@@ -791,6 +802,12 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
switch (areq)
{
case AUTH_REQ_OK:
+ if (conn->channel_binding[0] == 'r' && !conn->channel_bound)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("Channel binding required but not offered by server\n"));
+ return STATUS_ERROR;
+ }
break;
case AUTH_REQ_KRB4:
@@ -919,6 +936,17 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
{
char *password;
+ if (conn->channel_binding[0] == 'r')
+ {
+ if (areq == AUTH_REQ_PASSWORD)
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("Channel binding required but server requested cleartext password authentication\n"));
+ else
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("Channel binding required but server requested MD5 authentication\n"));
+ return STATUS_ERROR;
+ }
+
conn->password_needed = true;
password = conn->connhost[conn->whichhost].password;
if (password == NULL)
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index fa5af18ffac..e9627c06ec1 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -124,6 +124,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
#define DefaultTty ""
#define DefaultOption ""
#define DefaultAuthtype ""
+#define DefaultChannelBinding "prefer"
#define DefaultTargetSessionAttrs "any"
#ifdef USE_SSL
#define DefaultSSLMode "prefer"
@@ -211,6 +212,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Database-Password-File", "", 64,
offsetof(struct pg_conn, pgpassfile)},
+ {"channel_binding", "PGCHANNELBINDING", NULL, NULL,
+ "Channel-Binding", "", 7, /* sizeof("require") */
+ offsetof(struct pg_conn, channel_binding)},
+
{"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
"Connect-timeout", "", 10, /* strlen(INT32_MAX) == 10 */
offsetof(struct pg_conn, connect_timeout)},
@@ -556,6 +561,7 @@ pqDropServerData(PGconn *conn)
conn->last_sqlstate[0] = '\0';
conn->auth_req_received = false;
conn->password_needed = false;
+ conn->channel_bound = false;
conn->write_failed = false;
if (conn->write_err_msg)
free(conn->write_err_msg);
@@ -1197,6 +1203,28 @@ connectOptions2(PGconn *conn)
}
}
+ /*
+ * validate channel_binding option
+ */
+ if (conn->channel_binding)
+ {
+ if (strcmp(conn->channel_binding, "prefer") != 0
+ && strcmp(conn->channel_binding, "require") != 0)
+ {
+ conn->status = CONNECTION_BAD;
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("invalid channel_binding value: \"%s\"\n"),
+ conn->channel_binding);
+ return false;
+ }
+ }
+ else
+ {
+ conn->channel_binding = strdup(DefaultChannelBinding);
+ if (!conn->channel_binding)
+ goto oom_error;
+ }
+
/*
* validate sslmode option
*/
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index d37bb3ce404..70a5b445d72 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -347,6 +347,7 @@ struct pg_conn
char *pguser; /* Postgres username and password, if any */
char *pgpass;
char *pgpassfile; /* path to a file containing password(s) */
+ char *channel_binding; /* channel binding mode (require,prefer) */
char *keepalives; /* use TCP keepalives? */
char *keepalives_idle; /* time between TCP keepalives */
char *keepalives_interval; /* time between TCP keepalive
@@ -410,6 +411,7 @@ struct pg_conn
int sversion; /* server version, e.g. 70401 for 7.4.1 */
bool auth_req_received; /* true if any type of auth req received */
bool password_needed; /* true if server demanded a password */
+ bool channel_bound; /* true if channel_binding happened */
bool sigpipe_so; /* have we masked SIGPIPE via SO_NOSIGPIPE? */
bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */
bool write_failed; /* have we had a write failure on sock? */
--
2.17.1
view thread (46+ messages) latest in thread
Message-ID: <4863222980d349a6251065ea67f00ac41dedb162.camel@j-davis.com>
Permalink: ../4863222980d349a6251065ea67f00ac41dedb162.camel@j-davis.com/
Also on: postgresql.org/message-id/4863222980d349a6251065ea67f00ac41dedb162.camel@j-davis.com
copy link · copy postgr.es · copy git am
reply Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: pgsql@j-davis.com, michael@paquier.xyz, jkatz@postgresql.org, sfrost@snowman.net, peter.eisentraut@2ndquadrant.com
Subject: Re: Add "password_protocol" connection parameter to libpq
In-Reply-To: <4863222980d349a6251065ea67f00ac41dedb162.camel@j-davis.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox