Commit 86ab28fb authored by Peter Eisentraut's avatar Peter Eisentraut

Check channel binding flag at end of SCRAM exchange

We need to check whether the channel-binding flag encoded in the
client-final-message is the same one sent in the client-first-message.
Reviewed-by: default avatarMichael Paquier <michael.paquier@gmail.com>
parent 143b54d2
...@@ -110,6 +110,7 @@ typedef struct ...@@ -110,6 +110,7 @@ typedef struct
const char *username; /* username from startup packet */ const char *username; /* username from startup packet */
char cbind_flag;
bool ssl_in_use; bool ssl_in_use;
const char *tls_finished_message; const char *tls_finished_message;
size_t tls_finished_len; size_t tls_finished_len;
...@@ -788,6 +789,7 @@ read_client_first_message(scram_state *state, char *input) ...@@ -788,6 +789,7 @@ read_client_first_message(scram_state *state, char *input)
* Read gs2-cbind-flag. (For details see also RFC 5802 Section 6 "Channel * Read gs2-cbind-flag. (For details see also RFC 5802 Section 6 "Channel
* Binding".) * Binding".)
*/ */
state->cbind_flag = *input;
switch (*input) switch (*input)
{ {
case 'n': case 'n':
...@@ -1111,6 +1113,8 @@ read_client_final_message(scram_state *state, char *input) ...@@ -1111,6 +1113,8 @@ read_client_final_message(scram_state *state, char *input)
char *b64_message; char *b64_message;
int b64_message_len; int b64_message_len;
Assert(state->cbind_flag == 'p');
/* /*
* Fetch data appropriate for channel binding type * Fetch data appropriate for channel binding type
*/ */
...@@ -1155,10 +1159,11 @@ read_client_final_message(scram_state *state, char *input) ...@@ -1155,10 +1159,11 @@ read_client_final_message(scram_state *state, char *input)
/* /*
* If we are not using channel binding, the binding data is expected * If we are not using channel binding, the binding data is expected
* to always be "biws", which is "n,," base64-encoded, or "eSws", * to always be "biws", which is "n,," base64-encoded, or "eSws",
* which is "y,,". * which is "y,,". We also have to check whether the flag is the same
* one that the client originally sent.
*/ */
if (strcmp(channel_binding, "biws") != 0 && if (!(strcmp(channel_binding, "biws") == 0 && state->cbind_flag == 'n') &&
strcmp(channel_binding, "eSws") != 0) !(strcmp(channel_binding, "eSws") == 0 && state->cbind_flag == 'y'))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION), (errcode(ERRCODE_PROTOCOL_VIOLATION),
(errmsg("unexpected SCRAM channel-binding attribute in client-final-message")))); (errmsg("unexpected SCRAM channel-binding attribute in client-final-message"))));
......
...@@ -437,6 +437,10 @@ build_client_final_message(fe_scram_state *state, PQExpBuffer errormessage) ...@@ -437,6 +437,10 @@ build_client_final_message(fe_scram_state *state, PQExpBuffer errormessage)
/* /*
* Construct client-final-message-without-proof. We need to remember it * Construct client-final-message-without-proof. We need to remember it
* for verifying the server proof in the final step of authentication. * for verifying the server proof in the final step of authentication.
*
* The channel binding flag handling (p/y/n) must be consistent with
* build_client_first_message(), because the server will check that it's
* the same flag both times.
*/ */
if (strcmp(state->sasl_mechanism, SCRAM_SHA256_PLUS_NAME) == 0) if (strcmp(state->sasl_mechanism, SCRAM_SHA256_PLUS_NAME) == 0)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment