diff options
Diffstat (limited to 'src/interfaces/libpq')
-rw-r--r-- | src/interfaces/libpq/fe-auth-scram.c | 79 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-auth.c | 25 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 8 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-secure-openssl.c | 28 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-int.h | 15 |
5 files changed, 52 insertions, 103 deletions
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index 8415bbb5c61..1d9c9371183 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -352,17 +352,9 @@ build_client_first_message(fe_scram_state *state) if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0) { Assert(conn->ssl_in_use); - appendPQExpBuffer(&buf, "p=%s", conn->scram_channel_binding); - } - else if (conn->scram_channel_binding == NULL || - strlen(conn->scram_channel_binding) == 0) - { - /* - * Client has chosen to not show to server that it supports channel - * binding. - */ - appendPQExpBuffer(&buf, "n"); + appendPQExpBuffer(&buf, "p=tls-server-end-point"); } +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH else if (conn->ssl_in_use) { /* @@ -370,6 +362,7 @@ build_client_first_message(fe_scram_state *state) */ appendPQExpBuffer(&buf, "y"); } +#endif else { /* @@ -432,60 +425,28 @@ build_client_final_message(fe_scram_state *state) */ if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0) { +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH char *cbind_data = NULL; size_t cbind_data_len = 0; size_t cbind_header_len; char *cbind_input; size_t cbind_input_len; - if (strcmp(conn->scram_channel_binding, SCRAM_CHANNEL_BINDING_TLS_UNIQUE) == 0) - { -#ifdef USE_SSL - cbind_data = pgtls_get_finished(state->conn, &cbind_data_len); - if (cbind_data == NULL) - goto oom_error; -#endif - } - else if (strcmp(conn->scram_channel_binding, - SCRAM_CHANNEL_BINDING_TLS_END_POINT) == 0) - { - /* Fetch hash data of server's SSL certificate */ -#ifdef USE_SSL - cbind_data = - pgtls_get_peer_certificate_hash(state->conn, - &cbind_data_len); - if (cbind_data == NULL) - { - /* error message is already set on error */ - return NULL; - } -#endif - } - else - { - /* should not happen */ - termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("invalid channel binding type\n")); - return NULL; - } - - /* should not happen */ - if (cbind_data == NULL || cbind_data_len == 0) + /* Fetch hash data of server's SSL certificate */ + cbind_data = + pgtls_get_peer_certificate_hash(state->conn, + &cbind_data_len); + if (cbind_data == NULL) { - if (cbind_data != NULL) - free(cbind_data); + /* error message is already set on error */ termPQExpBuffer(&buf); - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("empty channel binding data for channel binding type \"%s\"\n"), - conn->scram_channel_binding); return NULL; } appendPQExpBuffer(&buf, "c="); /* p=type,, */ - cbind_header_len = 4 + strlen(conn->scram_channel_binding); + cbind_header_len = strlen("p=tls-server-end-point,,"); cbind_input_len = cbind_header_len + cbind_data_len; cbind_input = malloc(cbind_input_len); if (!cbind_input) @@ -493,8 +454,7 @@ build_client_final_message(fe_scram_state *state) free(cbind_data); goto oom_error; } - snprintf(cbind_input, cbind_input_len, "p=%s,,", - conn->scram_channel_binding); + memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len); memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len); if (!enlargePQExpBuffer(&buf, pg_b64_enc_len(cbind_input_len))) @@ -508,12 +468,21 @@ build_client_final_message(fe_scram_state *state) free(cbind_data); free(cbind_input); +#else + /* + * Chose channel binding, but the SSL library doesn't support it. + * Shouldn't happen. + */ + termPQExpBuffer(&buf); + printfPQExpBuffer(&conn->errorMessage, + "channel binding not supported by this build\n"); + return NULL; +#endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */ } - else if (conn->scram_channel_binding == NULL || - strlen(conn->scram_channel_binding) == 0) - appendPQExpBuffer(&buf, "c=biws"); /* base64 of "n,," */ +#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH else if (conn->ssl_in_use) appendPQExpBuffer(&buf, "c=eSws"); /* base64 of "y,," */ +#endif else appendPQExpBuffer(&buf, "c=biws"); /* base64 of "n,," */ diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 09012c562d0..540aba98b37 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -530,11 +530,26 @@ pg_SASL_init(PGconn *conn, int payloadlen) * nothing else has already been picked. If we add more mechanisms, a * more refined priority mechanism might become necessary. */ - if (conn->ssl_in_use && - conn->scram_channel_binding && - strlen(conn->scram_channel_binding) > 0 && - strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0) - selected_mechanism = SCRAM_SHA_256_PLUS_NAME; + if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0) + { + if (conn->ssl_in_use) + selected_mechanism = SCRAM_SHA_256_PLUS_NAME; + else + { + /* + * The server offered SCRAM-SHA-256-PLUS, but the connection + * is not SSL-encrypted. That's not sane. Perhaps SSL was + * stripped by a proxy? There's no point in continuing, + * because the server will reject the connection anyway if we + * try authenticate without channel binding even though both + * the client and server supported it. The SCRAM exchange + * checks for that, to prevent downgrade attacks. + */ + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection\n")); + goto error; + } + } else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 && !selected_mechanism) selected_mechanism = SCRAM_SHA_256_NAME; diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4b35994394a..221f1ecdaf8 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -123,7 +123,6 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options, #define DefaultOption "" #define DefaultAuthtype "" #define DefaultTargetSessionAttrs "any" -#define DefaultSCRAMChannelBinding SCRAM_CHANNEL_BINDING_TLS_UNIQUE #ifdef USE_SSL #define DefaultSSLMode "prefer" #else @@ -264,11 +263,6 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */ 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 * client can still handle SSL modes "disable" and "allow". Other @@ -3481,8 +3475,6 @@ freePGconn(PGconn *conn) free(conn->keepalives_interval); if (conn->keepalives_count) free(conn->keepalives_count); - if (conn->scram_channel_binding) - free(conn->scram_channel_binding); if (conn->sslmode) free(conn->sslmode); if (conn->sslcert) diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 045405e92bc..bbae8eff813 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -369,30 +369,10 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len) return n; } -char * -pgtls_get_finished(PGconn *conn, size_t *len) -{ - char dummy[1]; - char *result; - - /* - * OpenSSL does not offer an API to get directly the length of the TLS - * Finished message sent, so first do a dummy call to grab this - * information and then do an allocation with the correct size. - */ - *len = SSL_get_finished(conn->ssl, dummy, sizeof(dummy)); - result = malloc(*len); - if (result == NULL) - return NULL; - (void) SSL_get_finished(conn->ssl, result, *len); - - return result; -} - +#ifdef HAVE_X509_GET_SIGNATURE_NID char * pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) { -#ifdef HAVE_X509_GET_SIGNATURE_NID X509 *peer_cert; const EVP_MD *algo_type; unsigned char hash[EVP_MAX_MD_SIZE]; /* size for SHA-512 */ @@ -462,12 +442,8 @@ pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len) *len = hash_size; return cert_hash; -#else - printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("channel binding type \"tls-server-end-point\" is not supported by this build\n")); - return NULL; -#endif } +#endif /* HAVE_X509_GET_SIGNATURE_NID */ /* ------------------------------------------------------------ */ /* OpenSSL specific code */ diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 9a586ff25a4..4a836b186ef 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -349,7 +349,6 @@ struct pg_conn * retransmits */ char *keepalives_count; /* maximum number of TCP keepalive * retransmits */ - char *scram_channel_binding; /* SCRAM channel binding type */ char *sslmode; /* SSL mode (require,prefer,allow,disable) */ char *sslcompression; /* SSL compression (0 or 1) */ char *sslkey; /* client key filename */ @@ -716,21 +715,19 @@ extern bool pgtls_read_pending(PGconn *conn); extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len); /* - * Get the TLS finish message sent during last handshake. - * - * This information is useful for callers doing channel binding during - * authentication. - */ -extern char *pgtls_get_finished(PGconn *conn, size_t *len); - -/* * Get the hash of the server certificate, for SCRAM channel binding type * tls-server-end-point. * * NULL is sent back to the caller in the event of an error, with an * error message for the caller to consume. + * + * This is not supported with old versions of OpenSSL that don't have + * the X509_get_signature_nid() function. */ +#if defined(USE_OPENSSL) && defined(HAVE_X509_GET_SIGNATURE_NID) +#define HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH extern char *pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len); +#endif /* * Verify that the server certificate matches the host name we connected to. |