|
|
@ -423,6 +423,14 @@ pg_SASL_init(PGconn *conn, int payloadlen) |
|
|
|
|
|
|
|
|
|
|
|
initPQExpBuffer(&mechanism_buf); |
|
|
|
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) |
|
|
|
if (conn->sasl_state) |
|
|
|
{ |
|
|
|
{ |
|
|
|
printfPQExpBuffer(&conn->errorMessage, |
|
|
|
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 |
|
|
|
* 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 |
|
|
|
* else if a channel binding type is set and if the client supports it |
|
|
|
* it. Pick SCRAM-SHA-256 if nothing else has already been picked. If |
|
|
|
* (and did not set channel_binding=disable). Pick SCRAM-SHA-256 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 (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0) |
|
|
|
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 |
|
|
|
* The server has offered SCRAM-SHA-256-PLUS, which is only |
|
|
|
* supported by the client if a hash of the peer certificate |
|
|
|
* 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 |
|
|
|
#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 |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
@ -493,6 +502,14 @@ pg_SASL_init(PGconn *conn, int payloadlen) |
|
|
|
selected_mechanism = SCRAM_SHA_256_NAME; |
|
|
|
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) |
|
|
|
if (!selected_mechanism) |
|
|
|
{ |
|
|
|
{ |
|
|
|
printfPQExpBuffer(&conn->errorMessage, |
|
|
|
printfPQExpBuffer(&conn->errorMessage, |
|
|
@ -774,6 +791,50 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) |
|
|
|
return ret; |
|
|
|
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 |
|
|
|
* pg_fe_sendauth |
|
|
|
* client demux routine for processing an authentication request |
|
|
|
* client demux routine for processing an authentication request |
|
|
@ -788,6 +849,9 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) |
|
|
|
int |
|
|
|
int |
|
|
|
pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) |
|
|
|
pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
if (!check_expected_areq(areq, conn)) |
|
|
|
|
|
|
|
return STATUS_ERROR; |
|
|
|
|
|
|
|
|
|
|
|
switch (areq) |
|
|
|
switch (areq) |
|
|
|
{ |
|
|
|
{ |
|
|
|
case AUTH_REQ_OK: |
|
|
|
case AUTH_REQ_OK: |
|
|
|