Skip to content

Commit f3049a6

Browse files
committed
Refactor channel binding code to fetch cbind_data only when necessary
As things stand now, channel binding data is fetched from OpenSSL and saved into the SCRAM exchange context for any SSL connection attempted for a SCRAM authentication, resulting in data fetched but not used if no channel binding is used or if a different channel binding type is used than what the data is here for. Refactor the code in such a way that binding data is fetched from the SSL stack only when a specific channel binding is used for both the frontend and the backend. In order to achieve that, save the libpq connection context directly in the SCRAM exchange state, and add a dependency to SSL in the low-level SCRAM routines. This makes the interface in charge of initializing the SCRAM context cleaner as all its data comes from either PGconn* (for frontend) or Port* (for the backend). Author: Michael Paquier <michael.paquier@gmail.com>
1 parent 3ad2afc commit f3049a6

File tree

6 files changed

+102
-152
lines changed

6 files changed

+102
-152
lines changed

src/backend/libpq/auth-scram.c

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,8 @@ typedef struct
110110

111111
const char *username; /* username from startup packet */
112112

113+
Port *port;
113114
char cbind_flag;
114-
bool ssl_in_use;
115-
const char *tls_finished_message;
116-
size_t tls_finished_len;
117115
char *channel_binding_type;
118116

119117
int iterations;
@@ -172,21 +170,15 @@ static char *scram_mock_salt(const char *username);
172170
* it will fail, as if an incorrect password was given.
173171
*/
174172
void *
175-
pg_be_scram_init(const char *username,
176-
const char *shadow_pass,
177-
bool ssl_in_use,
178-
const char *tls_finished_message,
179-
size_t tls_finished_len)
173+
pg_be_scram_init(Port *port,
174+
const char *shadow_pass)
180175
{
181176
scram_state *state;
182177
bool got_verifier;
183178

184179
state = (scram_state *) palloc0(sizeof(scram_state));
180+
state->port = port;
185181
state->state = SCRAM_AUTH_INIT;
186-
state->username = username;
187-
state->ssl_in_use = ssl_in_use;
188-
state->tls_finished_message = tls_finished_message;
189-
state->tls_finished_len = tls_finished_len;
190182
state->channel_binding_type = NULL;
191183

192184
/*
@@ -209,7 +201,7 @@ pg_be_scram_init(const char *username,
209201
*/
210202
ereport(LOG,
211203
(errmsg("invalid SCRAM verifier for user \"%s\"",
212-
username)));
204+
state->port->user_name)));
213205
got_verifier = false;
214206
}
215207
}
@@ -220,7 +212,7 @@ pg_be_scram_init(const char *username,
220212
* authentication with an MD5 hash.)
221213
*/
222214
state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier."),
223-
state->username);
215+
state->port->user_name);
224216
got_verifier = false;
225217
}
226218
}
@@ -242,8 +234,8 @@ pg_be_scram_init(const char *username,
242234
*/
243235
if (!got_verifier)
244236
{
245-
mock_scram_verifier(username, &state->iterations, &state->salt,
246-
state->StoredKey, state->ServerKey);
237+
mock_scram_verifier(state->port->user_name, &state->iterations,
238+
&state->salt, state->StoredKey, state->ServerKey);
247239
state->doomed = true;
248240
}
249241

@@ -815,7 +807,7 @@ read_client_first_message(scram_state *state, char *input)
815807
* it supports channel binding, which in this implementation is
816808
* the case if a connection is using SSL.
817809
*/
818-
if (state->ssl_in_use)
810+
if (state->port->ssl_in_use)
819811
ereport(ERROR,
820812
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
821813
errmsg("SCRAM channel binding negotiation error"),
@@ -839,7 +831,7 @@ read_client_first_message(scram_state *state, char *input)
839831
{
840832
char *channel_binding_type;
841833

842-
if (!state->ssl_in_use)
834+
if (!state->port->ssl_in_use)
843835
{
844836
/*
845837
* Without SSL, we don't support channel binding.
@@ -1120,8 +1112,9 @@ read_client_final_message(scram_state *state, char *input)
11201112
*/
11211113
if (strcmp(state->channel_binding_type, SCRAM_CHANNEL_BINDING_TLS_UNIQUE) == 0)
11221114
{
1123-
cbind_data = state->tls_finished_message;
1124-
cbind_data_len = state->tls_finished_len;
1115+
#ifdef USE_SSL
1116+
cbind_data = be_tls_get_peer_finished(state->port, &cbind_data_len);
1117+
#endif
11251118
}
11261119
else
11271120
{

src/backend/libpq/auth.c

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -873,8 +873,6 @@ CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
873873
int inputlen;
874874
int result;
875875
bool initial;
876-
char *tls_finished = NULL;
877-
size_t tls_finished_len = 0;
878876

879877
/*
880878
* SASL auth is not supported for protocol versions before 3, because it
@@ -915,17 +913,6 @@ CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
915913
sendAuthRequest(port, AUTH_REQ_SASL, sasl_mechs, p - sasl_mechs + 1);
916914
pfree(sasl_mechs);
917915

918-
#ifdef USE_SSL
919-
920-
/*
921-
* Get data for channel binding.
922-
*/
923-
if (port->ssl_in_use)
924-
{
925-
tls_finished = be_tls_get_peer_finished(port, &tls_finished_len);
926-
}
927-
#endif
928-
929916
/*
930917
* Initialize the status tracker for message exchanges.
931918
*
@@ -937,11 +924,7 @@ CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
937924
* This is because we don't want to reveal to an attacker what usernames
938925
* are valid, nor which users have a valid password.
939926
*/
940-
scram_opaq = pg_be_scram_init(port->user_name,
941-
shadow_pass,
942-
port->ssl_in_use,
943-
tls_finished,
944-
tls_finished_len);
927+
scram_opaq = pg_be_scram_init(port, shadow_pass);
945928

946929
/*
947930
* Loop through SASL message exchange. This exchange can consist of

src/include/libpq/scram.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313
#ifndef PG_SCRAM_H
1414
#define PG_SCRAM_H
1515

16+
#include "libpq/libpq-be.h"
17+
1618
/* Status codes for message exchange */
1719
#define SASL_EXCHANGE_CONTINUE 0
1820
#define SASL_EXCHANGE_SUCCESS 1
1921
#define SASL_EXCHANGE_FAILURE 2
2022

2123
/* Routines dedicated to authentication */
22-
extern void *pg_be_scram_init(const char *username, const char *shadow_pass,
23-
bool ssl_in_use, const char *tls_finished_message,
24-
size_t tls_finished_len);
24+
extern void *pg_be_scram_init(Port *port, const char *shadow_pass);
2525
extern int pg_be_scram_exchange(void *opaq, char *input, int inputlen,
2626
char **output, int *outputlen, char **logdetail);
2727

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy