mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Add libpq parameter 'channel_binding'.
Allow clients to require channel binding to enhance security against untrusted servers. Author: Jeff Davis Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/227015d8417f2b4fef03f8966dbfa5cbcc4f44da.camel%40j-davis.com
This commit is contained in:
@ -423,6 +423,14 @@ pg_SASL_init(PGconn *conn, int payloadlen)
|
||||
|
||||
initPQExpBuffer(&mechanism_buf);
|
||||
|
||||
if (conn->channel_binding[0] == 'r' && /* require */
|
||||
!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,
|
||||
@ -454,10 +462,10 @@ pg_SASL_init(PGconn *conn, int payloadlen)
|
||||
|
||||
/*
|
||||
* Select the mechanism to use. Pick SCRAM-SHA-256-PLUS over anything
|
||||
* else if a channel binding type is set and if the client supports
|
||||
* it. Pick SCRAM-SHA-256 if nothing else has already been picked. If
|
||||
* we add more mechanisms, a more refined priority mechanism might
|
||||
* become necessary.
|
||||
* else if a channel binding type is set and if the client supports it
|
||||
* (and did not set channel_binding=disable). Pick SCRAM-SHA-256 if
|
||||
* nothing else has already been picked. If we add more mechanisms, a
|
||||
* more refined priority mechanism might become necessary.
|
||||
*/
|
||||
if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0)
|
||||
{
|
||||
@ -466,10 +474,11 @@ pg_SASL_init(PGconn *conn, int payloadlen)
|
||||
/*
|
||||
* The server has offered SCRAM-SHA-256-PLUS, which is only
|
||||
* supported by the client if a hash of the peer certificate
|
||||
* can be created.
|
||||
* can be created, and if channel_binding is not disabled.
|
||||
*/
|
||||
#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
|
||||
selected_mechanism = SCRAM_SHA_256_PLUS_NAME;
|
||||
if (conn->channel_binding[0] != 'd') /* disable */
|
||||
selected_mechanism = SCRAM_SHA_256_PLUS_NAME;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -493,6 +502,14 @@ pg_SASL_init(PGconn *conn, int payloadlen)
|
||||
selected_mechanism = SCRAM_SHA_256_NAME;
|
||||
}
|
||||
|
||||
if (conn->channel_binding[0] == 'r' && /* require */
|
||||
strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("channel binding is required, but server did not offer an authentication method that supports channel binding\n"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!selected_mechanism)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
@ -774,6 +791,50 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the authentication request is expected, given the connection
|
||||
* parameters. This is especially important when the client wishes to
|
||||
* authenticate the server before any sensitive information is exchanged.
|
||||
*/
|
||||
static bool
|
||||
check_expected_areq(AuthRequest areq, PGconn *conn)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
/*
|
||||
* When channel_binding=require, we must protect against two cases: (1) we
|
||||
* must not respond to non-SASL authentication requests, which might leak
|
||||
* information such as the client's password; and (2) even if we receive
|
||||
* AUTH_REQ_OK, we still must ensure that channel binding has happened in
|
||||
* order to authenticate the server.
|
||||
*/
|
||||
if (conn->channel_binding[0] == 'r' /* require */ )
|
||||
{
|
||||
switch (areq)
|
||||
{
|
||||
case AUTH_REQ_SASL:
|
||||
case AUTH_REQ_SASL_CONT:
|
||||
case AUTH_REQ_SASL_FIN:
|
||||
break;
|
||||
case AUTH_REQ_OK:
|
||||
if (!pg_fe_scram_channel_bound(conn->sasl_state))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("Channel binding required, but server authenticated client without channel binding\n"));
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("Channel binding required but not supported by server's authentication request\n"));
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_fe_sendauth
|
||||
* client demux routine for processing an authentication request
|
||||
@ -788,6 +849,9 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
|
||||
int
|
||||
pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
|
||||
{
|
||||
if (!check_expected_areq(areq, conn))
|
||||
return STATUS_ERROR;
|
||||
|
||||
switch (areq)
|
||||
{
|
||||
case AUTH_REQ_OK:
|
||||
|
Reference in New Issue
Block a user