From d9214f8a63608369bc1e70b8468799dcc8ab718a Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 10 Oct 2017 21:49:37 +0900 Subject: [PATCH 3/4] Add connection parameters "saslname" and "saslchannelbinding" Those parameters can be used to respectively enforce the value of the SASL mechanism name and the channel binding name sent to server during a SASL message exchange. A set of tests dedicated to SASL and channel binding is added as well to the SSL test suite, which is handy to check the validity of a patch. --- doc/src/sgml/libpq.sgml | 24 ++++++++++++++++++++++++ src/backend/libpq/auth-scram.c | 1 + src/interfaces/libpq/fe-auth.c | 9 ++++++++- src/interfaces/libpq/fe-connect.c | 13 +++++++++++++ src/interfaces/libpq/libpq-int.h | 2 ++ src/test/ssl/t/002_sasl.pl | 18 +++++++++++++++--- 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 0aedd837dc..5709f4098c 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1222,6 +1222,30 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname + + saslname + + + Controls the name of the SASL mechanism name sent to server when doing + a message exchange for a SASL authentication. The list of SASL + mechanisms supported by server are listed in + . + + + + + + saslchannelbinding + + + Controls the name of the channel binding name 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/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 2efc198459..a90abf4c3b 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -1097,6 +1097,7 @@ read_client_final_message(scram_state *state, char *input) * client has to provide channel binding value if needed. */ channel_binding = read_attr_value(&p, 'c'); + #ifdef USE_SSL if (state->ssl_in_use && state->channel_binding) diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index fa24c88522..97de9a0a30 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -569,6 +569,13 @@ pg_SASL_init(PGconn *conn, int payloadlen) } } + /* + * If user has asked for a specific mechanism name, enforce the chosen + * name to it. + */ + if (conn->saslname && strlen(conn->saslname) > 0) + selected_mechanism = conn->saslname; + if (!selected_mechanism) { printfPQExpBuffer(&conn->errorMessage, @@ -617,7 +624,7 @@ pg_SASL_init(PGconn *conn, int payloadlen) conn->ssl_in_use, channel_binding_advertised, selected_mechanism, - NULL, /* default channel binding */ + conn->saslchannelbinding, tls_finished, tls_finished_len); if (!conn->sasl_state) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 5f79803607..1d964b0ca0 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -262,6 +262,15 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ offsetof(struct pg_conn, keepalives_count)}, + /* Set of options proper to SASL */ + {"saslname", NULL, NULL, NULL, + "SASL-Name", "", 21, /* maximum name size per IANA == 21 */ + offsetof(struct pg_conn, saslname)}, + + {"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 @@ -3470,6 +3479,10 @@ freePGconn(PGconn *conn) free(conn->keepalives_interval); if (conn->keepalives_count) free(conn->keepalives_count); + if (conn->saslname) + free(conn->saslname); + 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 0eb8b60c95..6d500aa5db 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -349,6 +349,8 @@ struct pg_conn * retransmits */ char *keepalives_count; /* maximum number of TCP keepalive * retransmits */ + char *saslname; /* SASL mechanism name */ + char *saslchannelbinding; /* channel binding 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_sasl.pl b/src/test/ssl/t/002_sasl.pl index d43a970b55..e9226903ca 100644 --- a/src/test/ssl/t/002_sasl.pl +++ b/src/test/ssl/t/002_sasl.pl @@ -2,7 +2,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 1; +use Test::More tests => 6; use ServerSetup; use File::Copy; @@ -37,5 +37,17 @@ $common_connstr = "user=ssltestuser dbname=trustdb sslmode=require hostaddr=$SERVERHOSTADDR"; # Tests with default channel binding and SASL mechanism names. -# tls-unique is used here with channel binding. -test_connect_ok($common_connstr, ""); +# tls-unique is used here +test_connect_ok($common_connstr, "saslname=SCRAM-SHA-256-PLUS"); +test_connect_fails($common_connstr, "saslname=not-exists"); +# Having a client willing to not use channel binding should work, and +# so should this series. +test_connect_ok($common_connstr, "saslname=SCRAM-SHA-256"); +test_connect_ok($common_connstr, + "saslname=SCRAM-SHA-256 saslchannelbinding=tls-unique"); + +# Channel bindings +test_connect_ok($common_connstr, + "saslname=SCRAM-SHA-256-PLUS saslchannelbinding=tls-unique"); +test_connect_fails($common_connstr, + "saslname=SCRAM-SHA-256-PLUS saslchannelbinding=not-exists"); -- 2.14.2