From b9ee2d9432a0f16cdd59c9789a064d68f0220ad0 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 21 Nov 2017 12:55:29 +0900 Subject: [PATCH 1/2] Add connection parameter "saslchannelbinding" This parameter can be used to enforce the value of the type of channel binding used during a SASL message exchange. This proves to be useful now to check code paths where an invalid channel binding type is used by a client, which is limited, but will be more useful to allow clients to enforce the channel binding type to tls-enpoint once it gets added. More tests dedicated to SASL and channel binding are added as well to the SSL test suite, which is handy to check the validity of this patch. --- doc/src/sgml/libpq.sgml | 12 ++++++++++++ src/interfaces/libpq/fe-auth-scram.c | 10 ++++++++-- src/interfaces/libpq/fe-auth.c | 1 + src/interfaces/libpq/fe-auth.h | 1 + src/interfaces/libpq/fe-connect.c | 7 +++++++ src/interfaces/libpq/libpq-int.h | 1 + src/test/ssl/t/002_scram.pl | 11 ++++++++++- 7 files changed, 40 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 4703309254..2ad2061e9e 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1222,6 +1222,18 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + saslchannelbinding + + + Controls the name of the channel binding type sent to server when doing + a message exchange for a SASL authentication. The list of channel + binding names supported by server are listed in + . + + + + sslmode diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index f2403147ca..9860f6b15e 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -94,6 +94,7 @@ pg_fe_scram_init(const char *username, const char *password, bool ssl_in_use, const char *sasl_mechanism, + const char *channel_binding_type, char *tls_finished_message, size_t tls_finished_len) { @@ -120,9 +121,14 @@ pg_fe_scram_init(const char *username, } /* - * Store channel binding type. Only one type is currently supported. + * Store channel binding type. Only one type is currently supported, + * tls-unique, which is also the default. Anything defined by the caller + * is forcibly used. */ - state->channel_binding_type = SCRAM_CHANNEL_BINDING_TLS_UNIQUE; + if (channel_binding_type && strlen(channel_binding_type) > 0) + state->channel_binding_type = channel_binding_type; + else + state->channel_binding_type = SCRAM_CHANNEL_BINDING_TLS_UNIQUE; /* Normalize the password with SASLprep, if possible */ rc = pg_saslprep(password, &prep_password); diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 9d394919ef..2f34340f45 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -590,6 +590,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) password, conn->ssl_in_use, selected_mechanism, + conn->saslchannelbinding, tls_finished, tls_finished_len); if (!conn->sasl_state) diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h index 1525a52742..96094b0c1e 100644 --- a/src/interfaces/libpq/fe-auth.h +++ b/src/interfaces/libpq/fe-auth.h @@ -27,6 +27,7 @@ extern void *pg_fe_scram_init(const char *username, const char *password, bool ssl_in_use, const char *sasl_mechanism, + const char *channel_binding_type, char *tls_finished_message, size_t tls_finished_len); extern void pg_fe_scram_free(void *opaq); diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 2c175a2a24..3c85501754 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -262,6 +262,11 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, keepalives_count)}, + /* Set of options proper to SASL */ + {"saslchannelbinding", NULL, NULL, NULL, + "SASL-Channel", "", 22, /* sizeof("tls-unique-for-telnet") == 22 */ + offsetof(struct pg_conn, saslchannelbinding)}, + /* * ssl options are allowed even without client SSL support because the * client can still handle SSL modes "disable" and "allow". Other @@ -3469,6 +3474,8 @@ freePGconn(PGconn *conn) free(conn->keepalives_interval); if (conn->keepalives_count) free(conn->keepalives_count); + if (conn->saslchannelbinding) + free(conn->saslchannelbinding); if (conn->sslmode) free(conn->sslmode); if (conn->sslcert) diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 8412ee8160..1cb096f1ef 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -349,6 +349,7 @@ struct pg_conn * retransmits */ char *keepalives_count; /* maximum number of TCP keepalive * retransmits */ + char *saslchannelbinding; /* channel binding type used in SASL */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ char *sslcompression; /* SSL compression (0 or 1) */ char *sslkey; /* client key filename */ diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl index 25f75bd52a..c0b9599920 100644 --- a/src/test/ssl/t/002_scram.pl +++ b/src/test/ssl/t/002_scram.pl @@ -4,7 +4,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 1; +use Test::More tests => 3; use ServerSetup; use File::Copy; @@ -34,5 +34,14 @@ $ENV{PGPASSWORD} = "pass"; $common_connstr = "user=ssltestuser dbname=trustdb sslmode=require hostaddr=$SERVERHOSTADDR"; +# Defaut settings test_connect_ok($common_connstr, '', "SCRAM authentication with default channel binding"); + +# Channel bindings +test_connect_ok($common_connstr, + "saslchannelbinding=tls-unique", + "SCRAM authentication with tls-unique as channel binding"); +test_connect_fails($common_connstr, + "saslchannelbinding=not-exists", + "SCRAM authentication with invalid channel binding"); -- 2.15.0