mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Add libpq connection parameter "scram_channel_binding"
This parameter can be used to enforce the channel binding type used during a SCRAM authentication. This can be useful to check code paths where an invalid channel binding type is used by a client and will be even more useful to allow testing other channel binding types when they are added. The default value is tls-unique, which is what RFC 5802 specifies. Clients can optionally specify an empty value, which has as effect to not use channel binding and use SCRAM-SHA-256 as chosen SASL mechanism. More tests for SCRAM and channel binding are added to the SSL test suite. Author: Author: Michael Paquier <michael.paquier@gmail.com>
This commit is contained in:
parent
ab9e0e718a
commit
4bbf110d2f
@ -1222,6 +1222,30 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="libpq-scram-channel-binding" xreflabel="scram_channel_binding">
|
||||||
|
<term><literal>scram_channel_binding</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies the channel binding type to use with SCRAM authentication.
|
||||||
|
The list of channel binding types supported by server are listed in
|
||||||
|
<xref linkend="sasl-authentication"/>. An empty value specifies that
|
||||||
|
the client will not use channel binding. The default value is
|
||||||
|
<literal>tls-unique</literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Channel binding is only supported on SSL connections. If the
|
||||||
|
connection is not using SSL, then this setting is ignored.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This parameter is mainly intended for protocol testing. In normal
|
||||||
|
use, there should not be a need to choose a channel binding type other
|
||||||
|
than the default one.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="libpq-connect-sslmode" xreflabel="sslmode">
|
<varlistentry id="libpq-connect-sslmode" xreflabel="sslmode">
|
||||||
<term><literal>sslmode</literal></term>
|
<term><literal>sslmode</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -93,6 +93,7 @@ pg_fe_scram_init(const char *username,
|
|||||||
const char *password,
|
const char *password,
|
||||||
bool ssl_in_use,
|
bool ssl_in_use,
|
||||||
const char *sasl_mechanism,
|
const char *sasl_mechanism,
|
||||||
|
const char *channel_binding_type,
|
||||||
char *tls_finished_message,
|
char *tls_finished_message,
|
||||||
size_t tls_finished_len)
|
size_t tls_finished_len)
|
||||||
{
|
{
|
||||||
@ -112,17 +113,14 @@ pg_fe_scram_init(const char *username,
|
|||||||
state->tls_finished_message = tls_finished_message;
|
state->tls_finished_message = tls_finished_message;
|
||||||
state->tls_finished_len = tls_finished_len;
|
state->tls_finished_len = tls_finished_len;
|
||||||
state->sasl_mechanism = strdup(sasl_mechanism);
|
state->sasl_mechanism = strdup(sasl_mechanism);
|
||||||
|
state->channel_binding_type = channel_binding_type;
|
||||||
|
|
||||||
if (!state->sasl_mechanism)
|
if (!state->sasl_mechanism)
|
||||||
{
|
{
|
||||||
free(state);
|
free(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Store channel binding type. Only one type is currently supported.
|
|
||||||
*/
|
|
||||||
state->channel_binding_type = SCRAM_CHANNEL_BINDING_TLS_UNIQUE;
|
|
||||||
|
|
||||||
/* Normalize the password with SASLprep, if possible */
|
/* Normalize the password with SASLprep, if possible */
|
||||||
rc = pg_saslprep(password, &prep_password);
|
rc = pg_saslprep(password, &prep_password);
|
||||||
if (rc == SASLPREP_OOM)
|
if (rc == SASLPREP_OOM)
|
||||||
@ -375,6 +373,15 @@ build_client_first_message(fe_scram_state *state, PQExpBuffer errormessage)
|
|||||||
Assert(state->ssl_in_use);
|
Assert(state->ssl_in_use);
|
||||||
appendPQExpBuffer(&buf, "p=%s", state->channel_binding_type);
|
appendPQExpBuffer(&buf, "p=%s", state->channel_binding_type);
|
||||||
}
|
}
|
||||||
|
else if (state->channel_binding_type == NULL ||
|
||||||
|
strlen(state->channel_binding_type) == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Client has chosen to not show to server that it supports channel
|
||||||
|
* binding.
|
||||||
|
*/
|
||||||
|
appendPQExpBuffer(&buf, "n");
|
||||||
|
}
|
||||||
else if (state->ssl_in_use)
|
else if (state->ssl_in_use)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -493,6 +500,9 @@ build_client_final_message(fe_scram_state *state, PQExpBuffer errormessage)
|
|||||||
|
|
||||||
free(cbind_input);
|
free(cbind_input);
|
||||||
}
|
}
|
||||||
|
else if (state->channel_binding_type == NULL ||
|
||||||
|
strlen(state->channel_binding_type) == 0)
|
||||||
|
appendPQExpBuffer(&buf, "c=biws"); /* base64 of "n,," */
|
||||||
else if (state->ssl_in_use)
|
else if (state->ssl_in_use)
|
||||||
appendPQExpBuffer(&buf, "c=eSws"); /* base64 of "y,," */
|
appendPQExpBuffer(&buf, "c=eSws"); /* base64 of "y,," */
|
||||||
else
|
else
|
||||||
|
@ -528,11 +528,13 @@ pg_SASL_init(PGconn *conn, int payloadlen)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Select the mechanism to use. Pick SCRAM-SHA-256-PLUS over anything
|
* Select the mechanism to use. Pick SCRAM-SHA-256-PLUS over anything
|
||||||
* else. Pick SCRAM-SHA-256 if nothing else has already been picked.
|
* else if a channel binding type is set. Pick SCRAM-SHA-256 if
|
||||||
* If we add more mechanisms, a more refined priority mechanism might
|
* nothing else has already been picked. If we add more mechanisms, a
|
||||||
* become necessary.
|
* more refined priority mechanism might become necessary.
|
||||||
*/
|
*/
|
||||||
if (conn->ssl_in_use &&
|
if (conn->ssl_in_use &&
|
||||||
|
conn->scram_channel_binding &&
|
||||||
|
strlen(conn->scram_channel_binding) > 0 &&
|
||||||
strcmp(mechanism_buf.data, SCRAM_SHA256_PLUS_NAME) == 0)
|
strcmp(mechanism_buf.data, SCRAM_SHA256_PLUS_NAME) == 0)
|
||||||
selected_mechanism = SCRAM_SHA256_PLUS_NAME;
|
selected_mechanism = SCRAM_SHA256_PLUS_NAME;
|
||||||
else if (strcmp(mechanism_buf.data, SCRAM_SHA256_NAME) == 0 &&
|
else if (strcmp(mechanism_buf.data, SCRAM_SHA256_NAME) == 0 &&
|
||||||
@ -591,6 +593,7 @@ pg_SASL_init(PGconn *conn, int payloadlen)
|
|||||||
password,
|
password,
|
||||||
conn->ssl_in_use,
|
conn->ssl_in_use,
|
||||||
selected_mechanism,
|
selected_mechanism,
|
||||||
|
conn->scram_channel_binding,
|
||||||
tls_finished,
|
tls_finished,
|
||||||
tls_finished_len);
|
tls_finished_len);
|
||||||
if (!conn->sasl_state)
|
if (!conn->sasl_state)
|
||||||
|
@ -27,6 +27,7 @@ extern void *pg_fe_scram_init(const char *username,
|
|||||||
const char *password,
|
const char *password,
|
||||||
bool ssl_in_use,
|
bool ssl_in_use,
|
||||||
const char *sasl_mechanism,
|
const char *sasl_mechanism,
|
||||||
|
const char *channel_binding_type,
|
||||||
char *tls_finished_message,
|
char *tls_finished_message,
|
||||||
size_t tls_finished_len);
|
size_t tls_finished_len);
|
||||||
extern void pg_fe_scram_free(void *opaq);
|
extern void pg_fe_scram_free(void *opaq);
|
||||||
|
@ -71,6 +71,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common/ip.h"
|
#include "common/ip.h"
|
||||||
|
#include "common/scram-common.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "port/pg_bswap.h"
|
#include "port/pg_bswap.h"
|
||||||
|
|
||||||
@ -122,6 +123,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
|
|||||||
#define DefaultOption ""
|
#define DefaultOption ""
|
||||||
#define DefaultAuthtype ""
|
#define DefaultAuthtype ""
|
||||||
#define DefaultTargetSessionAttrs "any"
|
#define DefaultTargetSessionAttrs "any"
|
||||||
|
#define DefaultSCRAMChannelBinding SCRAM_CHANNEL_BINDING_TLS_UNIQUE
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
#define DefaultSSLMode "prefer"
|
#define DefaultSSLMode "prefer"
|
||||||
#else
|
#else
|
||||||
@ -262,6 +264,11 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
|
|||||||
"TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */
|
"TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */
|
||||||
offsetof(struct pg_conn, keepalives_count)},
|
offsetof(struct pg_conn, keepalives_count)},
|
||||||
|
|
||||||
|
{"scram_channel_binding", NULL, DefaultSCRAMChannelBinding, NULL,
|
||||||
|
"SCRAM-Channel-Binding", "D",
|
||||||
|
21, /* sizeof("tls-server-end-point") == 21 */
|
||||||
|
offsetof(struct pg_conn, scram_channel_binding)},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ssl options are allowed even without client SSL support because the
|
* ssl options are allowed even without client SSL support because the
|
||||||
* client can still handle SSL modes "disable" and "allow". Other
|
* client can still handle SSL modes "disable" and "allow". Other
|
||||||
@ -3469,6 +3476,8 @@ freePGconn(PGconn *conn)
|
|||||||
free(conn->keepalives_interval);
|
free(conn->keepalives_interval);
|
||||||
if (conn->keepalives_count)
|
if (conn->keepalives_count)
|
||||||
free(conn->keepalives_count);
|
free(conn->keepalives_count);
|
||||||
|
if (conn->scram_channel_binding)
|
||||||
|
free(conn->scram_channel_binding);
|
||||||
if (conn->sslmode)
|
if (conn->sslmode)
|
||||||
free(conn->sslmode);
|
free(conn->sslmode);
|
||||||
if (conn->sslcert)
|
if (conn->sslcert)
|
||||||
|
@ -349,6 +349,7 @@ struct pg_conn
|
|||||||
* retransmits */
|
* retransmits */
|
||||||
char *keepalives_count; /* maximum number of TCP keepalive
|
char *keepalives_count; /* maximum number of TCP keepalive
|
||||||
* retransmits */
|
* retransmits */
|
||||||
|
char *scram_channel_binding; /* SCRAM channel binding type */
|
||||||
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
|
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
|
||||||
char *sslcompression; /* SSL compression (0 or 1) */
|
char *sslcompression; /* SSL compression (0 or 1) */
|
||||||
char *sslkey; /* client key filename */
|
char *sslkey; /* client key filename */
|
||||||
|
@ -4,7 +4,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 1;
|
use Test::More tests => 4;
|
||||||
use ServerSetup;
|
use ServerSetup;
|
||||||
use File::Copy;
|
use File::Copy;
|
||||||
|
|
||||||
@ -34,5 +34,17 @@ $ENV{PGPASSWORD} = "pass";
|
|||||||
$common_connstr =
|
$common_connstr =
|
||||||
"user=ssltestuser dbname=trustdb sslmode=require hostaddr=$SERVERHOSTADDR";
|
"user=ssltestuser dbname=trustdb sslmode=require hostaddr=$SERVERHOSTADDR";
|
||||||
|
|
||||||
|
# Default settings
|
||||||
test_connect_ok($common_connstr, '',
|
test_connect_ok($common_connstr, '',
|
||||||
"SCRAM authentication with default channel binding");
|
"SCRAM authentication with default channel binding");
|
||||||
|
|
||||||
|
# Channel binding settings
|
||||||
|
test_connect_ok($common_connstr,
|
||||||
|
"scram_channel_binding=tls-unique",
|
||||||
|
"SCRAM authentication with tls-unique as channel binding");
|
||||||
|
test_connect_ok($common_connstr,
|
||||||
|
"scram_channel_binding=''",
|
||||||
|
"SCRAM authentication without channel binding");
|
||||||
|
test_connect_fails($common_connstr,
|
||||||
|
"scram_channel_binding=not-exists",
|
||||||
|
"SCRAM authentication with invalid channel binding");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user