LCOV - code coverage report
Current view: top level - src/backend/libpq - auth-scram.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 20.7 % 502 104
Test Date: 2026-01-26 10:56:24 Functions: 15.8 % 19 3
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 6.1 % 392 24

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * auth-scram.c
       4                 :             :  *        Server-side implementation of the SASL SCRAM-SHA-256 mechanism.
       5                 :             :  *
       6                 :             :  * See the following RFCs for more details:
       7                 :             :  * - RFC 5802: https://tools.ietf.org/html/rfc5802
       8                 :             :  * - RFC 5803: https://tools.ietf.org/html/rfc5803
       9                 :             :  * - RFC 7677: https://tools.ietf.org/html/rfc7677
      10                 :             :  *
      11                 :             :  * Here are some differences:
      12                 :             :  *
      13                 :             :  * - Username from the authentication exchange is not used. The client
      14                 :             :  *       should send an empty string as the username.
      15                 :             :  *
      16                 :             :  * - If the password isn't valid UTF-8, or contains characters prohibited
      17                 :             :  *       by the SASLprep profile, we skip the SASLprep pre-processing and use
      18                 :             :  *       the raw bytes in calculating the hash.
      19                 :             :  *
      20                 :             :  * - If channel binding is used, the channel binding type is always
      21                 :             :  *       "tls-server-end-point".  The spec says the default is "tls-unique"
      22                 :             :  *       (RFC 5802, section 6.1. Default Channel Binding), but there are some
      23                 :             :  *       problems with that.  Firstly, not all SSL libraries provide an API to
      24                 :             :  *       get the TLS Finished message, required to use "tls-unique".  Secondly,
      25                 :             :  *       "tls-unique" is not specified for TLS v1.3, and as of this writing,
      26                 :             :  *       it's not clear if there will be a replacement.  We could support both
      27                 :             :  *       "tls-server-end-point" and "tls-unique", but for our use case,
      28                 :             :  *       "tls-unique" doesn't really have any advantages.  The main advantage
      29                 :             :  *       of "tls-unique" would be that it works even if the server doesn't
      30                 :             :  *       have a certificate, but PostgreSQL requires a server certificate
      31                 :             :  *       whenever SSL is used, anyway.
      32                 :             :  *
      33                 :             :  *
      34                 :             :  * The password stored in pg_authid consists of the iteration count, salt,
      35                 :             :  * StoredKey and ServerKey.
      36                 :             :  *
      37                 :             :  * SASLprep usage
      38                 :             :  * --------------
      39                 :             :  *
      40                 :             :  * One notable difference to the SCRAM specification is that while the
      41                 :             :  * specification dictates that the password is in UTF-8, and prohibits
      42                 :             :  * certain characters, we are more lenient.  If the password isn't a valid
      43                 :             :  * UTF-8 string, or contains prohibited characters, the raw bytes are used
      44                 :             :  * to calculate the hash instead, without SASLprep processing.  This is
      45                 :             :  * because PostgreSQL supports other encodings too, and the encoding being
      46                 :             :  * used during authentication is undefined (client_encoding isn't set until
      47                 :             :  * after authentication).  In effect, we try to interpret the password as
      48                 :             :  * UTF-8 and apply SASLprep processing, but if it looks invalid, we assume
      49                 :             :  * that it's in some other encoding.
      50                 :             :  *
      51                 :             :  * In the worst case, we misinterpret a password that's in a different
      52                 :             :  * encoding as being Unicode, because it happens to consists entirely of
      53                 :             :  * valid UTF-8 bytes, and we apply Unicode normalization to it.  As long
      54                 :             :  * as we do that consistently, that will not lead to failed logins.
      55                 :             :  * Fortunately, the UTF-8 byte sequences that are ignored by SASLprep
      56                 :             :  * don't correspond to any commonly used characters in any of the other
      57                 :             :  * supported encodings, so it should not lead to any significant loss in
      58                 :             :  * entropy, even if the normalization is incorrectly applied to a
      59                 :             :  * non-UTF-8 password.
      60                 :             :  *
      61                 :             :  * Error handling
      62                 :             :  * --------------
      63                 :             :  *
      64                 :             :  * Don't reveal user information to an unauthenticated client.  We don't
      65                 :             :  * want an attacker to be able to probe whether a particular username is
      66                 :             :  * valid.  In SCRAM, the server has to read the salt and iteration count
      67                 :             :  * from the user's stored secret, and send it to the client.  To avoid
      68                 :             :  * revealing whether a user exists, when the client tries to authenticate
      69                 :             :  * with a username that doesn't exist, or doesn't have a valid SCRAM
      70                 :             :  * secret in pg_authid, we create a fake salt and iteration count
      71                 :             :  * on-the-fly, and proceed with the authentication with that.  In the end,
      72                 :             :  * we'll reject the attempt, as if an incorrect password was given.  When
      73                 :             :  * we are performing a "mock" authentication, the 'doomed' flag in
      74                 :             :  * scram_state is set.
      75                 :             :  *
      76                 :             :  * In the error messages, avoid printing strings from the client, unless
      77                 :             :  * you check that they are pure ASCII.  We don't want an unauthenticated
      78                 :             :  * attacker to be able to spam the logs with characters that are not valid
      79                 :             :  * to the encoding being used, whatever that is.  We cannot avoid that in
      80                 :             :  * general, after logging in, but let's do what we can here.
      81                 :             :  *
      82                 :             :  *
      83                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      84                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      85                 :             :  *
      86                 :             :  * src/backend/libpq/auth-scram.c
      87                 :             :  *
      88                 :             :  *-------------------------------------------------------------------------
      89                 :             :  */
      90                 :             : #include "postgres.h"
      91                 :             : 
      92                 :             : #include <unistd.h>
      93                 :             : 
      94                 :             : #include "access/xlog.h"
      95                 :             : #include "catalog/pg_control.h"
      96                 :             : #include "common/base64.h"
      97                 :             : #include "common/hmac.h"
      98                 :             : #include "common/saslprep.h"
      99                 :             : #include "common/scram-common.h"
     100                 :             : #include "common/sha2.h"
     101                 :             : #include "libpq/crypt.h"
     102                 :             : #include "libpq/sasl.h"
     103                 :             : #include "libpq/scram.h"
     104                 :             : #include "miscadmin.h"
     105                 :             : 
     106                 :             : static void scram_get_mechanisms(Port *port, StringInfo buf);
     107                 :             : static void *scram_init(Port *port, const char *selected_mech,
     108                 :             :                                                 const char *shadow_pass);
     109                 :             : static int      scram_exchange(void *opaq, const char *input, int inputlen,
     110                 :             :                                                    char **output, int *outputlen,
     111                 :             :                                                    const char **logdetail);
     112                 :             : 
     113                 :             : /* Mechanism declaration */
     114                 :             : const pg_be_sasl_mech pg_be_scram_mech = {
     115                 :             :         scram_get_mechanisms,
     116                 :             :         scram_init,
     117                 :             :         scram_exchange,
     118                 :             : 
     119                 :             :         PG_MAX_SASL_MESSAGE_LENGTH
     120                 :             : };
     121                 :             : 
     122                 :             : /*
     123                 :             :  * Status data for a SCRAM authentication exchange.  This should be kept
     124                 :             :  * internal to this file.
     125                 :             :  */
     126                 :             : typedef enum
     127                 :             : {
     128                 :             :         SCRAM_AUTH_INIT,
     129                 :             :         SCRAM_AUTH_SALT_SENT,
     130                 :             :         SCRAM_AUTH_FINISHED,
     131                 :             : } scram_state_enum;
     132                 :             : 
     133                 :             : typedef struct
     134                 :             : {
     135                 :             :         scram_state_enum state;
     136                 :             : 
     137                 :             :         Port       *port;
     138                 :             :         bool            channel_binding_in_use;
     139                 :             : 
     140                 :             :         /* State data depending on the hash type */
     141                 :             :         pg_cryptohash_type hash_type;
     142                 :             :         int                     key_length;
     143                 :             : 
     144                 :             :         int                     iterations;
     145                 :             :         char       *salt;                       /* base64-encoded */
     146                 :             :         uint8           ClientKey[SCRAM_MAX_KEY_LEN];
     147                 :             :         uint8           StoredKey[SCRAM_MAX_KEY_LEN];
     148                 :             :         uint8           ServerKey[SCRAM_MAX_KEY_LEN];
     149                 :             : 
     150                 :             :         /* Fields of the first message from client */
     151                 :             :         char            cbind_flag;
     152                 :             :         char       *client_first_message_bare;
     153                 :             :         char       *client_username;
     154                 :             :         char       *client_nonce;
     155                 :             : 
     156                 :             :         /* Fields from the last message from client */
     157                 :             :         char       *client_final_message_without_proof;
     158                 :             :         char       *client_final_nonce;
     159                 :             :         uint8           ClientProof[SCRAM_MAX_KEY_LEN];
     160                 :             : 
     161                 :             :         /* Fields generated in the server */
     162                 :             :         char       *server_first_message;
     163                 :             :         char       *server_nonce;
     164                 :             : 
     165                 :             :         /*
     166                 :             :          * If something goes wrong during the authentication, or we are performing
     167                 :             :          * a "mock" authentication (see comments at top of file), the 'doomed'
     168                 :             :          * flag is set.  A reason for the failure, for the server log, is put in
     169                 :             :          * 'logdetail'.
     170                 :             :          */
     171                 :             :         bool            doomed;
     172                 :             :         char       *logdetail;
     173                 :             : } scram_state;
     174                 :             : 
     175                 :             : static void read_client_first_message(scram_state *state, const char *input);
     176                 :             : static void read_client_final_message(scram_state *state, const char *input);
     177                 :             : static char *build_server_first_message(scram_state *state);
     178                 :             : static char *build_server_final_message(scram_state *state);
     179                 :             : static bool verify_client_proof(scram_state *state);
     180                 :             : static bool verify_final_nonce(scram_state *state);
     181                 :             : static void mock_scram_secret(const char *username, pg_cryptohash_type *hash_type,
     182                 :             :                                                           int *iterations, int *key_length, char **salt,
     183                 :             :                                                           uint8 *stored_key, uint8 *server_key);
     184                 :             : static bool is_scram_printable(char *p);
     185                 :             : static char *sanitize_char(char c);
     186                 :             : static char *sanitize_str(const char *s);
     187                 :             : static uint8 *scram_mock_salt(const char *username,
     188                 :             :                                                           pg_cryptohash_type hash_type,
     189                 :             :                                                           int key_length);
     190                 :             : 
     191                 :             : /*
     192                 :             :  * The number of iterations to use when generating new secrets.
     193                 :             :  */
     194                 :             : int                     scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
     195                 :             : 
     196                 :             : /*
     197                 :             :  * Get a list of SASL mechanisms that this module supports.
     198                 :             :  *
     199                 :             :  * For the convenience of building the FE/BE packet that lists the
     200                 :             :  * mechanisms, the names are appended to the given StringInfo buffer,
     201                 :             :  * separated by '\0' bytes.
     202                 :             :  */
     203                 :             : static void
     204                 :           0 : scram_get_mechanisms(Port *port, StringInfo buf)
     205                 :             : {
     206                 :             :         /*
     207                 :             :          * Advertise the mechanisms in decreasing order of importance.  So the
     208                 :             :          * channel-binding variants go first, if they are supported.  Channel
     209                 :             :          * binding is only supported with SSL.
     210                 :             :          */
     211                 :             : #ifdef USE_SSL
     212         [ #  # ]:           0 :         if (port->ssl_in_use)
     213                 :             :         {
     214                 :           0 :                 appendStringInfoString(buf, SCRAM_SHA_256_PLUS_NAME);
     215                 :           0 :                 appendStringInfoChar(buf, '\0');
     216                 :           0 :         }
     217                 :             : #endif
     218                 :           0 :         appendStringInfoString(buf, SCRAM_SHA_256_NAME);
     219                 :           0 :         appendStringInfoChar(buf, '\0');
     220                 :           0 : }
     221                 :             : 
     222                 :             : /*
     223                 :             :  * Initialize a new SCRAM authentication exchange status tracker.  This
     224                 :             :  * needs to be called before doing any exchange.  It will be filled later
     225                 :             :  * after the beginning of the exchange with authentication information.
     226                 :             :  *
     227                 :             :  * 'selected_mech' identifies the SASL mechanism that the client selected.
     228                 :             :  * It should be one of the mechanisms that we support, as returned by
     229                 :             :  * scram_get_mechanisms().
     230                 :             :  *
     231                 :             :  * 'shadow_pass' is the role's stored secret, from pg_authid.rolpassword.
     232                 :             :  * The username was provided by the client in the startup message, and is
     233                 :             :  * available in port->user_name.  If 'shadow_pass' is NULL, we still perform
     234                 :             :  * an authentication exchange, but it will fail, as if an incorrect password
     235                 :             :  * was given.
     236                 :             :  */
     237                 :             : static void *
     238                 :           0 : scram_init(Port *port, const char *selected_mech, const char *shadow_pass)
     239                 :             : {
     240                 :           0 :         scram_state *state;
     241                 :           0 :         bool            got_secret;
     242                 :             : 
     243                 :           0 :         state = palloc0_object(scram_state);
     244                 :           0 :         state->port = port;
     245                 :           0 :         state->state = SCRAM_AUTH_INIT;
     246                 :             : 
     247                 :             :         /*
     248                 :             :          * Parse the selected mechanism.
     249                 :             :          *
     250                 :             :          * Note that if we don't support channel binding, or if we're not using
     251                 :             :          * SSL at all, we would not have advertised the PLUS variant in the first
     252                 :             :          * place.  If the client nevertheless tries to select it, it's a protocol
     253                 :             :          * violation like selecting any other SASL mechanism we don't support.
     254                 :             :          */
     255                 :             : #ifdef USE_SSL
     256   [ #  #  #  # ]:           0 :         if (strcmp(selected_mech, SCRAM_SHA_256_PLUS_NAME) == 0 && port->ssl_in_use)
     257                 :           0 :                 state->channel_binding_in_use = true;
     258                 :             :         else
     259                 :             : #endif
     260         [ #  # ]:           0 :         if (strcmp(selected_mech, SCRAM_SHA_256_NAME) == 0)
     261                 :           0 :                 state->channel_binding_in_use = false;
     262                 :             :         else
     263   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     264                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     265                 :             :                                  errmsg("client selected an invalid SASL authentication mechanism")));
     266                 :             : 
     267                 :             :         /*
     268                 :             :          * Parse the stored secret.
     269                 :             :          */
     270         [ #  # ]:           0 :         if (shadow_pass)
     271                 :             :         {
     272                 :           0 :                 int                     password_type = get_password_type(shadow_pass);
     273                 :             : 
     274         [ #  # ]:           0 :                 if (password_type == PASSWORD_TYPE_SCRAM_SHA_256)
     275                 :             :                 {
     276   [ #  #  #  # ]:           0 :                         if (parse_scram_secret(shadow_pass, &state->iterations,
     277                 :           0 :                                                                    &state->hash_type, &state->key_length,
     278                 :           0 :                                                                    &state->salt,
     279                 :           0 :                                                                    state->StoredKey,
     280                 :           0 :                                                                    state->ServerKey))
     281                 :           0 :                                 got_secret = true;
     282                 :             :                         else
     283                 :             :                         {
     284                 :             :                                 /*
     285                 :             :                                  * The password looked like a SCRAM secret, but could not be
     286                 :             :                                  * parsed.
     287                 :             :                                  */
     288   [ #  #  #  # ]:           0 :                                 ereport(LOG,
     289                 :             :                                                 (errmsg("invalid SCRAM secret for user \"%s\"",
     290                 :             :                                                                 state->port->user_name)));
     291                 :           0 :                                 got_secret = false;
     292                 :             :                         }
     293                 :           0 :                 }
     294                 :             :                 else
     295                 :             :                 {
     296                 :             :                         /*
     297                 :             :                          * The user doesn't have SCRAM secret. (You cannot do SCRAM
     298                 :             :                          * authentication with an MD5 hash.)
     299                 :             :                          */
     300                 :           0 :                         state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM secret."),
     301                 :           0 :                                                                                 state->port->user_name);
     302                 :           0 :                         got_secret = false;
     303                 :             :                 }
     304                 :           0 :         }
     305                 :             :         else
     306                 :             :         {
     307                 :             :                 /*
     308                 :             :                  * The caller requested us to perform a dummy authentication.  This is
     309                 :             :                  * considered normal, since the caller requested it, so don't set log
     310                 :             :                  * detail.
     311                 :             :                  */
     312                 :           0 :                 got_secret = false;
     313                 :             :         }
     314                 :             : 
     315                 :             :         /*
     316                 :             :          * If the user did not have a valid SCRAM secret, we still go through the
     317                 :             :          * motions with a mock one, and fail as if the client supplied an
     318                 :             :          * incorrect password.  This is to avoid revealing information to an
     319                 :             :          * attacker.
     320                 :             :          */
     321         [ #  # ]:           0 :         if (!got_secret)
     322                 :             :         {
     323                 :           0 :                 mock_scram_secret(state->port->user_name, &state->hash_type,
     324                 :           0 :                                                   &state->iterations, &state->key_length,
     325                 :           0 :                                                   &state->salt,
     326                 :           0 :                                                   state->StoredKey, state->ServerKey);
     327                 :           0 :                 state->doomed = true;
     328                 :           0 :         }
     329                 :             : 
     330                 :           0 :         return state;
     331                 :           0 : }
     332                 :             : 
     333                 :             : /*
     334                 :             :  * Continue a SCRAM authentication exchange.
     335                 :             :  *
     336                 :             :  * 'input' is the SCRAM payload sent by the client.  On the first call,
     337                 :             :  * 'input' contains the "Initial Client Response" that the client sent as
     338                 :             :  * part of the SASLInitialResponse message, or NULL if no Initial Client
     339                 :             :  * Response was given.  (The SASL specification distinguishes between an
     340                 :             :  * empty response and non-existing one.)  On subsequent calls, 'input'
     341                 :             :  * cannot be NULL.  For convenience in this function, the caller must
     342                 :             :  * ensure that there is a null terminator at input[inputlen].
     343                 :             :  *
     344                 :             :  * The next message to send to client is saved in 'output', for a length
     345                 :             :  * of 'outputlen'.  In the case of an error, optionally store a palloc'd
     346                 :             :  * string at *logdetail that will be sent to the postmaster log (but not
     347                 :             :  * the client).
     348                 :             :  */
     349                 :             : static int
     350                 :           0 : scram_exchange(void *opaq, const char *input, int inputlen,
     351                 :             :                            char **output, int *outputlen, const char **logdetail)
     352                 :             : {
     353                 :           0 :         scram_state *state = (scram_state *) opaq;
     354                 :           0 :         int                     result;
     355                 :             : 
     356                 :           0 :         *output = NULL;
     357                 :             : 
     358                 :             :         /*
     359                 :             :          * If the client didn't include an "Initial Client Response" in the
     360                 :             :          * SASLInitialResponse message, send an empty challenge, to which the
     361                 :             :          * client will respond with the same data that usually comes in the
     362                 :             :          * Initial Client Response.
     363                 :             :          */
     364         [ #  # ]:           0 :         if (input == NULL)
     365                 :             :         {
     366         [ #  # ]:           0 :                 Assert(state->state == SCRAM_AUTH_INIT);
     367                 :             : 
     368                 :           0 :                 *output = pstrdup("");
     369                 :           0 :                 *outputlen = 0;
     370                 :           0 :                 return PG_SASL_EXCHANGE_CONTINUE;
     371                 :             :         }
     372                 :             : 
     373                 :             :         /*
     374                 :             :          * Check that the input length agrees with the string length of the input.
     375                 :             :          * We can ignore inputlen after this.
     376                 :             :          */
     377         [ #  # ]:           0 :         if (inputlen == 0)
     378   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     379                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     380                 :             :                                  errmsg("malformed SCRAM message"),
     381                 :             :                                  errdetail("The message is empty.")));
     382         [ #  # ]:           0 :         if (inputlen != strlen(input))
     383   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     384                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     385                 :             :                                  errmsg("malformed SCRAM message"),
     386                 :             :                                  errdetail("Message length does not match input length.")));
     387                 :             : 
     388      [ #  #  # ]:           0 :         switch (state->state)
     389                 :             :         {
     390                 :             :                 case SCRAM_AUTH_INIT:
     391                 :             : 
     392                 :             :                         /*
     393                 :             :                          * Initialization phase.  Receive the first message from client
     394                 :             :                          * and be sure that it parsed correctly.  Then send the challenge
     395                 :             :                          * to the client.
     396                 :             :                          */
     397                 :           0 :                         read_client_first_message(state, input);
     398                 :             : 
     399                 :             :                         /* prepare message to send challenge */
     400                 :           0 :                         *output = build_server_first_message(state);
     401                 :             : 
     402                 :           0 :                         state->state = SCRAM_AUTH_SALT_SENT;
     403                 :           0 :                         result = PG_SASL_EXCHANGE_CONTINUE;
     404                 :           0 :                         break;
     405                 :             : 
     406                 :             :                 case SCRAM_AUTH_SALT_SENT:
     407                 :             : 
     408                 :             :                         /*
     409                 :             :                          * Final phase for the server.  Receive the response to the
     410                 :             :                          * challenge previously sent, verify, and let the client know that
     411                 :             :                          * everything went well (or not).
     412                 :             :                          */
     413                 :           0 :                         read_client_final_message(state, input);
     414                 :             : 
     415         [ #  # ]:           0 :                         if (!verify_final_nonce(state))
     416   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     417                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     418                 :             :                                                  errmsg("invalid SCRAM response"),
     419                 :             :                                                  errdetail("Nonce does not match.")));
     420                 :             : 
     421                 :             :                         /*
     422                 :             :                          * Now check the final nonce and the client proof.
     423                 :             :                          *
     424                 :             :                          * If we performed a "mock" authentication that we knew would fail
     425                 :             :                          * from the get go, this is where we fail.
     426                 :             :                          *
     427                 :             :                          * The SCRAM specification includes an error code,
     428                 :             :                          * "invalid-proof", for authentication failure, but it also allows
     429                 :             :                          * erroring out in an application-specific way.  We choose to do
     430                 :             :                          * the latter, so that the error message for invalid password is
     431                 :             :                          * the same for all authentication methods.  The caller will call
     432                 :             :                          * ereport(), when we return PG_SASL_EXCHANGE_FAILURE with no
     433                 :             :                          * output.
     434                 :             :                          *
     435                 :             :                          * NB: the order of these checks is intentional.  We calculate the
     436                 :             :                          * client proof even in a mock authentication, even though it's
     437                 :             :                          * bound to fail, to thwart timing attacks to determine if a role
     438                 :             :                          * with the given name exists or not.
     439                 :             :                          */
     440   [ #  #  #  # ]:           0 :                         if (!verify_client_proof(state) || state->doomed)
     441                 :             :                         {
     442                 :           0 :                                 result = PG_SASL_EXCHANGE_FAILURE;
     443                 :           0 :                                 break;
     444                 :             :                         }
     445                 :             : 
     446                 :             :                         /* Build final message for client */
     447                 :           0 :                         *output = build_server_final_message(state);
     448                 :             : 
     449                 :             :                         /* Success! */
     450                 :           0 :                         result = PG_SASL_EXCHANGE_SUCCESS;
     451                 :           0 :                         state->state = SCRAM_AUTH_FINISHED;
     452                 :           0 :                         break;
     453                 :             : 
     454                 :             :                 default:
     455   [ #  #  #  # ]:           0 :                         elog(ERROR, "invalid SCRAM exchange state");
     456                 :           0 :                         result = PG_SASL_EXCHANGE_FAILURE;
     457                 :           0 :         }
     458                 :             : 
     459   [ #  #  #  #  :           0 :         if (result == PG_SASL_EXCHANGE_FAILURE && state->logdetail && logdetail)
                   #  # ]
     460                 :           0 :                 *logdetail = state->logdetail;
     461                 :             : 
     462         [ #  # ]:           0 :         if (*output)
     463                 :           0 :                 *outputlen = strlen(*output);
     464                 :             : 
     465   [ #  #  #  # ]:           0 :         if (result == PG_SASL_EXCHANGE_SUCCESS && state->state == SCRAM_AUTH_FINISHED)
     466                 :             :         {
     467                 :           0 :                 memcpy(MyProcPort->scram_ClientKey, state->ClientKey, sizeof(MyProcPort->scram_ClientKey));
     468                 :           0 :                 memcpy(MyProcPort->scram_ServerKey, state->ServerKey, sizeof(MyProcPort->scram_ServerKey));
     469                 :           0 :                 MyProcPort->has_scram_keys = true;
     470                 :           0 :         }
     471                 :             : 
     472                 :           0 :         return result;
     473                 :           0 : }
     474                 :             : 
     475                 :             : /*
     476                 :             :  * Construct a SCRAM secret, for storing in pg_authid.rolpassword.
     477                 :             :  *
     478                 :             :  * The result is palloc'd, so caller is responsible for freeing it.
     479                 :             :  */
     480                 :             : char *
     481                 :           9 : pg_be_scram_build_secret(const char *password)
     482                 :             : {
     483                 :           9 :         char       *prep_password;
     484                 :           9 :         pg_saslprep_rc rc;
     485                 :           9 :         uint8           saltbuf[SCRAM_DEFAULT_SALT_LEN];
     486                 :           9 :         char       *result;
     487                 :           9 :         const char *errstr = NULL;
     488                 :             : 
     489                 :             :         /*
     490                 :             :          * Normalize the password with SASLprep.  If that doesn't work, because
     491                 :             :          * the password isn't valid UTF-8 or contains prohibited characters, just
     492                 :             :          * proceed with the original password.  (See comments at top of file.)
     493                 :             :          */
     494                 :           9 :         rc = pg_saslprep(password, &prep_password);
     495         [ -  + ]:           9 :         if (rc == SASLPREP_SUCCESS)
     496                 :           9 :                 password = (const char *) prep_password;
     497                 :             : 
     498                 :             :         /* Generate random salt */
     499         [ +  - ]:           9 :         if (!pg_strong_random(saltbuf, SCRAM_DEFAULT_SALT_LEN))
     500   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     501                 :             :                                 (errcode(ERRCODE_INTERNAL_ERROR),
     502                 :             :                                  errmsg("could not generate random salt")));
     503                 :             : 
     504                 :           9 :         result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN,
     505                 :           9 :                                                                 saltbuf, SCRAM_DEFAULT_SALT_LEN,
     506                 :           9 :                                                                 scram_sha_256_iterations, password,
     507                 :             :                                                                 &errstr);
     508                 :             : 
     509         [ -  + ]:           9 :         if (prep_password)
     510                 :           9 :                 pfree(prep_password);
     511                 :             : 
     512                 :          18 :         return result;
     513                 :           9 : }
     514                 :             : 
     515                 :             : /*
     516                 :             :  * Verify a plaintext password against a SCRAM secret.  This is used when
     517                 :             :  * performing plaintext password authentication for a user that has a SCRAM
     518                 :             :  * secret stored in pg_authid.
     519                 :             :  */
     520                 :             : bool
     521                 :           5 : scram_verify_plain_password(const char *username, const char *password,
     522                 :             :                                                         const char *secret)
     523                 :             : {
     524                 :           5 :         char       *encoded_salt;
     525                 :           5 :         uint8      *salt;
     526                 :           5 :         int                     saltlen;
     527                 :           5 :         int                     iterations;
     528                 :           5 :         int                     key_length = 0;
     529                 :           5 :         pg_cryptohash_type hash_type;
     530                 :           5 :         uint8           salted_password[SCRAM_MAX_KEY_LEN];
     531                 :           5 :         uint8           stored_key[SCRAM_MAX_KEY_LEN];
     532                 :           5 :         uint8           server_key[SCRAM_MAX_KEY_LEN];
     533                 :           5 :         uint8           computed_key[SCRAM_MAX_KEY_LEN];
     534                 :           5 :         char       *prep_password;
     535                 :           5 :         pg_saslprep_rc rc;
     536                 :           5 :         const char *errstr = NULL;
     537                 :             : 
     538   [ +  -  +  - ]:          10 :         if (!parse_scram_secret(secret, &iterations, &hash_type, &key_length,
     539                 :           5 :                                                         &encoded_salt, stored_key, server_key))
     540                 :             :         {
     541                 :             :                 /*
     542                 :             :                  * The password looked like a SCRAM secret, but could not be parsed.
     543                 :             :                  */
     544   [ #  #  #  # ]:           0 :                 ereport(LOG,
     545                 :             :                                 (errmsg("invalid SCRAM secret for user \"%s\"", username)));
     546                 :           0 :                 return false;
     547                 :             :         }
     548                 :             : 
     549                 :           5 :         saltlen = pg_b64_dec_len(strlen(encoded_salt));
     550                 :           5 :         salt = palloc(saltlen);
     551                 :          10 :         saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt,
     552                 :           5 :                                                         saltlen);
     553         [ +  - ]:           5 :         if (saltlen < 0)
     554                 :             :         {
     555   [ #  #  #  # ]:           0 :                 ereport(LOG,
     556                 :             :                                 (errmsg("invalid SCRAM secret for user \"%s\"", username)));
     557                 :           0 :                 return false;
     558                 :             :         }
     559                 :             : 
     560                 :             :         /* Normalize the password */
     561                 :           5 :         rc = pg_saslprep(password, &prep_password);
     562         [ -  + ]:           5 :         if (rc == SASLPREP_SUCCESS)
     563                 :           5 :                 password = prep_password;
     564                 :             : 
     565                 :             :         /* Compute Server Key based on the user-supplied plaintext password */
     566                 :          10 :         if (scram_SaltedPassword(password, hash_type, key_length,
     567                 :           5 :                                                          salt, saltlen, iterations,
     568   [ +  -  +  - ]:          10 :                                                          salted_password, &errstr) < 0 ||
     569                 :          10 :                 scram_ServerKey(salted_password, hash_type, key_length,
     570                 :          10 :                                                 computed_key, &errstr) < 0)
     571                 :             :         {
     572   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not compute server key: %s", errstr);
     573                 :           0 :         }
     574                 :             : 
     575         [ -  + ]:           5 :         if (prep_password)
     576                 :           5 :                 pfree(prep_password);
     577                 :             : 
     578                 :             :         /*
     579                 :             :          * Compare the secret's Server Key with the one computed from the
     580                 :             :          * user-supplied password.
     581                 :             :          */
     582                 :           5 :         return memcmp(computed_key, server_key, key_length) == 0;
     583                 :           5 : }
     584                 :             : 
     585                 :             : 
     586                 :             : /*
     587                 :             :  * Parse and validate format of given SCRAM secret.
     588                 :             :  *
     589                 :             :  * On success, the iteration count, salt, stored key, and server key are
     590                 :             :  * extracted from the secret, and returned to the caller.  For 'stored_key'
     591                 :             :  * and 'server_key', the caller must pass pre-allocated buffers of size
     592                 :             :  * SCRAM_MAX_KEY_LEN.  Salt is returned as a base64-encoded, null-terminated
     593                 :             :  * string.  The buffer for the salt is palloc'd by this function.
     594                 :             :  *
     595                 :             :  * Returns true if the SCRAM secret has been parsed, and false otherwise.
     596                 :             :  */
     597                 :             : bool
     598                 :          49 : parse_scram_secret(const char *secret, int *iterations,
     599                 :             :                                    pg_cryptohash_type *hash_type, int *key_length,
     600                 :             :                                    char **salt, uint8 *stored_key, uint8 *server_key)
     601                 :             : {
     602                 :          49 :         char       *v;
     603                 :          49 :         char       *p;
     604                 :          49 :         char       *scheme_str;
     605                 :          49 :         char       *salt_str;
     606                 :          49 :         char       *iterations_str;
     607                 :          49 :         char       *storedkey_str;
     608                 :          49 :         char       *serverkey_str;
     609                 :          49 :         int                     decoded_len;
     610                 :          49 :         uint8      *decoded_salt_buf;
     611                 :          49 :         uint8      *decoded_stored_buf;
     612                 :          49 :         uint8      *decoded_server_buf;
     613                 :             : 
     614                 :             :         /*
     615                 :             :          * The secret is of form:
     616                 :             :          *
     617                 :             :          * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
     618                 :             :          */
     619                 :          49 :         v = pstrdup(secret);
     620                 :          49 :         scheme_str = strsep(&v, "$");
     621         [ +  + ]:          49 :         if (v == NULL)
     622                 :          18 :                 goto invalid_secret;
     623                 :          31 :         iterations_str = strsep(&v, ":");
     624         [ +  + ]:          31 :         if (v == NULL)
     625                 :           2 :                 goto invalid_secret;
     626                 :          29 :         salt_str = strsep(&v, "$");
     627         [ +  - ]:          29 :         if (v == NULL)
     628                 :           0 :                 goto invalid_secret;
     629                 :          29 :         storedkey_str = strsep(&v, ":");
     630         [ +  - ]:          29 :         if (v == NULL)
     631                 :           0 :                 goto invalid_secret;
     632                 :          29 :         serverkey_str = v;
     633                 :             : 
     634                 :             :         /* Parse the fields */
     635         [ -  + ]:          29 :         if (strcmp(scheme_str, "SCRAM-SHA-256") != 0)
     636                 :           0 :                 goto invalid_secret;
     637                 :          29 :         *hash_type = PG_SHA256;
     638                 :          29 :         *key_length = SCRAM_SHA_256_KEY_LEN;
     639                 :             : 
     640                 :          29 :         errno = 0;
     641                 :          29 :         *iterations = strtol(iterations_str, &p, 10);
     642   [ +  -  -  + ]:          29 :         if (*p || errno != 0)
     643                 :           0 :                 goto invalid_secret;
     644                 :             : 
     645                 :             :         /*
     646                 :             :          * Verify that the salt is in Base64-encoded format, by decoding it,
     647                 :             :          * although we return the encoded version to the caller.
     648                 :             :          */
     649                 :          29 :         decoded_len = pg_b64_dec_len(strlen(salt_str));
     650                 :          29 :         decoded_salt_buf = palloc(decoded_len);
     651                 :          58 :         decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
     652                 :          29 :                                                                 decoded_salt_buf, decoded_len);
     653         [ +  - ]:          29 :         if (decoded_len < 0)
     654                 :           0 :                 goto invalid_secret;
     655                 :          29 :         *salt = pstrdup(salt_str);
     656                 :             : 
     657                 :             :         /*
     658                 :             :          * Decode StoredKey and ServerKey.
     659                 :             :          */
     660                 :          29 :         decoded_len = pg_b64_dec_len(strlen(storedkey_str));
     661                 :          29 :         decoded_stored_buf = palloc(decoded_len);
     662                 :          58 :         decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
     663                 :          29 :                                                                 decoded_stored_buf, decoded_len);
     664         [ +  + ]:          29 :         if (decoded_len != *key_length)
     665                 :           2 :                 goto invalid_secret;
     666                 :          27 :         memcpy(stored_key, decoded_stored_buf, *key_length);
     667                 :             : 
     668                 :          27 :         decoded_len = pg_b64_dec_len(strlen(serverkey_str));
     669                 :          27 :         decoded_server_buf = palloc(decoded_len);
     670                 :          54 :         decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
     671                 :          27 :                                                                 decoded_server_buf, decoded_len);
     672         [ +  + ]:          27 :         if (decoded_len != *key_length)
     673                 :           2 :                 goto invalid_secret;
     674                 :          25 :         memcpy(server_key, decoded_server_buf, *key_length);
     675                 :             : 
     676                 :          25 :         return true;
     677                 :             : 
     678                 :             : invalid_secret:
     679                 :          24 :         *salt = NULL;
     680                 :          24 :         return false;
     681                 :          49 : }
     682                 :             : 
     683                 :             : /*
     684                 :             :  * Generate plausible SCRAM secret parameters for mock authentication.
     685                 :             :  *
     686                 :             :  * In a normal authentication, these are extracted from the secret
     687                 :             :  * stored in the server.  This function generates values that look
     688                 :             :  * realistic, for when there is no stored secret, using SCRAM-SHA-256.
     689                 :             :  *
     690                 :             :  * Like in parse_scram_secret(), for 'stored_key' and 'server_key', the
     691                 :             :  * caller must pass pre-allocated buffers of size SCRAM_MAX_KEY_LEN, and
     692                 :             :  * the buffer for the salt is palloc'd by this function.
     693                 :             :  */
     694                 :             : static void
     695                 :           0 : mock_scram_secret(const char *username, pg_cryptohash_type *hash_type,
     696                 :             :                                   int *iterations, int *key_length, char **salt,
     697                 :             :                                   uint8 *stored_key, uint8 *server_key)
     698                 :             : {
     699                 :           0 :         uint8      *raw_salt;
     700                 :           0 :         char       *encoded_salt;
     701                 :           0 :         int                     encoded_len;
     702                 :             : 
     703                 :             :         /* Enforce the use of SHA-256, which would be realistic enough */
     704                 :           0 :         *hash_type = PG_SHA256;
     705                 :           0 :         *key_length = SCRAM_SHA_256_KEY_LEN;
     706                 :             : 
     707                 :             :         /*
     708                 :             :          * Generate deterministic salt.
     709                 :             :          *
     710                 :             :          * Note that we cannot reveal any information to an attacker here so the
     711                 :             :          * error messages need to remain generic.  This should never fail anyway
     712                 :             :          * as the salt generated for mock authentication uses the cluster's nonce
     713                 :             :          * value.
     714                 :             :          */
     715                 :           0 :         raw_salt = scram_mock_salt(username, *hash_type, *key_length);
     716         [ #  # ]:           0 :         if (raw_salt == NULL)
     717   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not encode salt");
     718                 :             : 
     719                 :           0 :         encoded_len = pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN);
     720                 :             :         /* don't forget the zero-terminator */
     721                 :           0 :         encoded_salt = (char *) palloc(encoded_len + 1);
     722                 :           0 :         encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt,
     723                 :           0 :                                                                 encoded_len);
     724                 :             : 
     725         [ #  # ]:           0 :         if (encoded_len < 0)
     726   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not encode salt");
     727                 :           0 :         encoded_salt[encoded_len] = '\0';
     728                 :             : 
     729                 :           0 :         *salt = encoded_salt;
     730                 :           0 :         *iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
     731                 :             : 
     732                 :             :         /* StoredKey and ServerKey are not used in a doomed authentication */
     733                 :           0 :         memset(stored_key, 0, SCRAM_MAX_KEY_LEN);
     734                 :           0 :         memset(server_key, 0, SCRAM_MAX_KEY_LEN);
     735                 :           0 : }
     736                 :             : 
     737                 :             : /*
     738                 :             :  * Read the value in a given SCRAM exchange message for given attribute.
     739                 :             :  */
     740                 :             : static char *
     741                 :           0 : read_attr_value(char **input, char attr)
     742                 :             : {
     743                 :           0 :         char       *begin = *input;
     744                 :           0 :         char       *end;
     745                 :             : 
     746         [ #  # ]:           0 :         if (*begin != attr)
     747   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     748                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     749                 :             :                                  errmsg("malformed SCRAM message"),
     750                 :             :                                  errdetail("Expected attribute \"%c\" but found \"%s\".",
     751                 :             :                                                    attr, sanitize_char(*begin))));
     752                 :           0 :         begin++;
     753                 :             : 
     754         [ #  # ]:           0 :         if (*begin != '=')
     755   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     756                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     757                 :             :                                  errmsg("malformed SCRAM message"),
     758                 :             :                                  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
     759                 :           0 :         begin++;
     760                 :             : 
     761                 :           0 :         end = begin;
     762   [ #  #  #  # ]:           0 :         while (*end && *end != ',')
     763                 :           0 :                 end++;
     764                 :             : 
     765         [ #  # ]:           0 :         if (*end)
     766                 :             :         {
     767                 :           0 :                 *end = '\0';
     768                 :           0 :                 *input = end + 1;
     769                 :           0 :         }
     770                 :             :         else
     771                 :           0 :                 *input = end;
     772                 :             : 
     773                 :           0 :         return begin;
     774                 :           0 : }
     775                 :             : 
     776                 :             : static bool
     777                 :           0 : is_scram_printable(char *p)
     778                 :             : {
     779                 :             :         /*------
     780                 :             :          * Printable characters, as defined by SCRAM spec: (RFC 5802)
     781                 :             :          *
     782                 :             :          *      printable               = %x21-2B / %x2D-7E
     783                 :             :          *                                        ;; Printable ASCII except ",".
     784                 :             :          *                                        ;; Note that any "printable" is also
     785                 :             :          *                                        ;; a valid "value".
     786                 :             :          *------
     787                 :             :          */
     788         [ #  # ]:           0 :         for (; *p; p++)
     789                 :             :         {
     790   [ #  #  #  #  :           0 :                 if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
                   #  # ]
     791                 :           0 :                         return false;
     792                 :           0 :         }
     793                 :           0 :         return true;
     794                 :           0 : }
     795                 :             : 
     796                 :             : /*
     797                 :             :  * Convert an arbitrary byte to printable form.  For error messages.
     798                 :             :  *
     799                 :             :  * If it's a printable ASCII character, print it as a single character.
     800                 :             :  * otherwise, print it in hex.
     801                 :             :  *
     802                 :             :  * The returned pointer points to a static buffer.
     803                 :             :  */
     804                 :             : static char *
     805                 :           0 : sanitize_char(char c)
     806                 :             : {
     807                 :             :         static char buf[5];
     808                 :             : 
     809   [ #  #  #  # ]:           0 :         if (c >= 0x21 && c <= 0x7E)
     810                 :           0 :                 snprintf(buf, sizeof(buf), "'%c'", c);
     811                 :             :         else
     812                 :           0 :                 snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
     813                 :           0 :         return buf;
     814                 :             : }
     815                 :             : 
     816                 :             : /*
     817                 :             :  * Convert an arbitrary string to printable form, for error messages.
     818                 :             :  *
     819                 :             :  * Anything that's not a printable ASCII character is replaced with
     820                 :             :  * '?', and the string is truncated at 30 characters.
     821                 :             :  *
     822                 :             :  * The returned pointer points to a static buffer.
     823                 :             :  */
     824                 :             : static char *
     825                 :           0 : sanitize_str(const char *s)
     826                 :             : {
     827                 :             :         static char buf[30 + 1];
     828                 :           0 :         int                     i;
     829                 :             : 
     830         [ #  # ]:           0 :         for (i = 0; i < sizeof(buf) - 1; i++)
     831                 :             :         {
     832                 :           0 :                 char            c = s[i];
     833                 :             : 
     834         [ #  # ]:           0 :                 if (c == '\0')
     835                 :           0 :                         break;
     836                 :             : 
     837   [ #  #  #  # ]:           0 :                 if (c >= 0x21 && c <= 0x7E)
     838                 :           0 :                         buf[i] = c;
     839                 :             :                 else
     840                 :           0 :                         buf[i] = '?';
     841      [ #  #  # ]:           0 :         }
     842                 :           0 :         buf[i] = '\0';
     843                 :           0 :         return buf;
     844                 :           0 : }
     845                 :             : 
     846                 :             : /*
     847                 :             :  * Read the next attribute and value in a SCRAM exchange message.
     848                 :             :  *
     849                 :             :  * The attribute character is set in *attr_p, the attribute value is the
     850                 :             :  * return value.
     851                 :             :  */
     852                 :             : static char *
     853                 :           0 : read_any_attr(char **input, char *attr_p)
     854                 :             : {
     855                 :           0 :         char       *begin = *input;
     856                 :           0 :         char       *end;
     857                 :           0 :         char            attr = *begin;
     858                 :             : 
     859         [ #  # ]:           0 :         if (attr == '\0')
     860   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     861                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     862                 :             :                                  errmsg("malformed SCRAM message"),
     863                 :             :                                  errdetail("Attribute expected, but found end of string.")));
     864                 :             : 
     865                 :             :         /*------
     866                 :             :          * attr-val                = ALPHA "=" value
     867                 :             :          *                                       ;; Generic syntax of any attribute sent
     868                 :             :          *                                       ;; by server or client
     869                 :             :          *------
     870                 :             :          */
     871   [ #  #  #  # ]:           0 :         if (!((attr >= 'A' && attr <= 'Z') ||
     872         [ #  # ]:           0 :                   (attr >= 'a' && attr <= 'z')))
     873   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     874                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     875                 :             :                                  errmsg("malformed SCRAM message"),
     876                 :             :                                  errdetail("Attribute expected, but found invalid character \"%s\".",
     877                 :             :                                                    sanitize_char(attr))));
     878         [ #  # ]:           0 :         if (attr_p)
     879                 :           0 :                 *attr_p = attr;
     880                 :           0 :         begin++;
     881                 :             : 
     882         [ #  # ]:           0 :         if (*begin != '=')
     883   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     884                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     885                 :             :                                  errmsg("malformed SCRAM message"),
     886                 :             :                                  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
     887                 :           0 :         begin++;
     888                 :             : 
     889                 :           0 :         end = begin;
     890   [ #  #  #  # ]:           0 :         while (*end && *end != ',')
     891                 :           0 :                 end++;
     892                 :             : 
     893         [ #  # ]:           0 :         if (*end)
     894                 :             :         {
     895                 :           0 :                 *end = '\0';
     896                 :           0 :                 *input = end + 1;
     897                 :           0 :         }
     898                 :             :         else
     899                 :           0 :                 *input = end;
     900                 :             : 
     901                 :           0 :         return begin;
     902                 :           0 : }
     903                 :             : 
     904                 :             : /*
     905                 :             :  * Read and parse the first message from client in the context of a SCRAM
     906                 :             :  * authentication exchange message.
     907                 :             :  *
     908                 :             :  * At this stage, any errors will be reported directly with ereport(ERROR).
     909                 :             :  */
     910                 :             : static void
     911                 :           0 : read_client_first_message(scram_state *state, const char *input)
     912                 :             : {
     913                 :           0 :         char       *p = pstrdup(input);
     914                 :           0 :         char       *channel_binding_type;
     915                 :             : 
     916                 :             : 
     917                 :             :         /*------
     918                 :             :          * The syntax for the client-first-message is: (RFC 5802)
     919                 :             :          *
     920                 :             :          * saslname                = 1*(value-safe-char / "=2C" / "=3D")
     921                 :             :          *                                       ;; Conforms to <value>.
     922                 :             :          *
     923                 :             :          * authzid                 = "a=" saslname
     924                 :             :          *                                       ;; Protocol specific.
     925                 :             :          *
     926                 :             :          * cb-name                 = 1*(ALPHA / DIGIT / "." / "-")
     927                 :             :          *                                        ;; See RFC 5056, Section 7.
     928                 :             :          *                                        ;; E.g., "tls-server-end-point" or
     929                 :             :          *                                        ;; "tls-unique".
     930                 :             :          *
     931                 :             :          * gs2-cbind-flag  = ("p=" cb-name) / "n" / "y"
     932                 :             :          *                                       ;; "n" -> client doesn't support channel binding.
     933                 :             :          *                                       ;; "y" -> client does support channel binding
     934                 :             :          *                                       ;;                but thinks the server does not.
     935                 :             :          *                                       ;; "p" -> client requires channel binding.
     936                 :             :          *                                       ;; The selected channel binding follows "p=".
     937                 :             :          *
     938                 :             :          * gs2-header      = gs2-cbind-flag "," [ authzid ] ","
     939                 :             :          *                                       ;; GS2 header for SCRAM
     940                 :             :          *                                       ;; (the actual GS2 header includes an optional
     941                 :             :          *                                       ;; flag to indicate that the GSS mechanism is not
     942                 :             :          *                                       ;; "standard", but since SCRAM is "standard", we
     943                 :             :          *                                       ;; don't include that flag).
     944                 :             :          *
     945                 :             :          * username                = "n=" saslname
     946                 :             :          *                                       ;; Usernames are prepared using SASLprep.
     947                 :             :          *
     948                 :             :          * reserved-mext  = "m=" 1*(value-char)
     949                 :             :          *                                       ;; Reserved for signaling mandatory extensions.
     950                 :             :          *                                       ;; The exact syntax will be defined in
     951                 :             :          *                                       ;; the future.
     952                 :             :          *
     953                 :             :          * nonce                   = "r=" c-nonce [s-nonce]
     954                 :             :          *                                       ;; Second part provided by server.
     955                 :             :          *
     956                 :             :          * c-nonce                 = printable
     957                 :             :          *
     958                 :             :          * client-first-message-bare =
     959                 :             :          *                                       [reserved-mext ","]
     960                 :             :          *                                       username "," nonce ["," extensions]
     961                 :             :          *
     962                 :             :          * client-first-message =
     963                 :             :          *                                       gs2-header client-first-message-bare
     964                 :             :          *
     965                 :             :          * For example:
     966                 :             :          * n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
     967                 :             :          *
     968                 :             :          * The "n,," in the beginning means that the client doesn't support
     969                 :             :          * channel binding, and no authzid is given.  "n=user" is the username.
     970                 :             :          * However, in PostgreSQL the username is sent in the startup packet, and
     971                 :             :          * the username in the SCRAM exchange is ignored.  libpq always sends it
     972                 :             :          * as an empty string.  The last part, "r=fyko+d2lbbFgONRv9qkxdawL" is
     973                 :             :          * the client nonce.
     974                 :             :          *------
     975                 :             :          */
     976                 :             : 
     977                 :             :         /*
     978                 :             :          * Read gs2-cbind-flag.  (For details see also RFC 5802 Section 6 "Channel
     979                 :             :          * Binding".)
     980                 :             :          */
     981                 :           0 :         state->cbind_flag = *p;
     982   [ #  #  #  # ]:           0 :         switch (*p)
     983                 :             :         {
     984                 :             :                 case 'n':
     985                 :             : 
     986                 :             :                         /*
     987                 :             :                          * The client does not support channel binding or has simply
     988                 :             :                          * decided to not use it.  In that case just let it go.
     989                 :             :                          */
     990         [ #  # ]:           0 :                         if (state->channel_binding_in_use)
     991   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     992                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     993                 :             :                                                  errmsg("malformed SCRAM message"),
     994                 :             :                                                  errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
     995                 :             : 
     996                 :           0 :                         p++;
     997         [ #  # ]:           0 :                         if (*p != ',')
     998   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     999                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1000                 :             :                                                  errmsg("malformed SCRAM message"),
    1001                 :             :                                                  errdetail("Comma expected, but found character \"%s\".",
    1002                 :             :                                                                    sanitize_char(*p))));
    1003                 :           0 :                         p++;
    1004                 :           0 :                         break;
    1005                 :             :                 case 'y':
    1006                 :             : 
    1007                 :             :                         /*
    1008                 :             :                          * The client supports channel binding and thinks that the server
    1009                 :             :                          * does not.  In this case, the server must fail authentication if
    1010                 :             :                          * it supports channel binding.
    1011                 :             :                          */
    1012         [ #  # ]:           0 :                         if (state->channel_binding_in_use)
    1013   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1014                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1015                 :             :                                                  errmsg("malformed SCRAM message"),
    1016                 :             :                                                  errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
    1017                 :             : 
    1018                 :             : #ifdef USE_SSL
    1019         [ #  # ]:           0 :                         if (state->port->ssl_in_use)
    1020   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1021                 :             :                                                 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
    1022                 :             :                                                  errmsg("SCRAM channel binding negotiation error"),
    1023                 :             :                                                  errdetail("The client supports SCRAM channel binding but thinks the server does not.  "
    1024                 :             :                                                                    "However, this server does support channel binding.")));
    1025                 :             : #endif
    1026                 :           0 :                         p++;
    1027         [ #  # ]:           0 :                         if (*p != ',')
    1028   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1029                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1030                 :             :                                                  errmsg("malformed SCRAM message"),
    1031                 :             :                                                  errdetail("Comma expected, but found character \"%s\".",
    1032                 :             :                                                                    sanitize_char(*p))));
    1033                 :           0 :                         p++;
    1034                 :           0 :                         break;
    1035                 :             :                 case 'p':
    1036                 :             : 
    1037                 :             :                         /*
    1038                 :             :                          * The client requires channel binding.  Channel binding type
    1039                 :             :                          * follows, e.g., "p=tls-server-end-point".
    1040                 :             :                          */
    1041         [ #  # ]:           0 :                         if (!state->channel_binding_in_use)
    1042   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1043                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1044                 :             :                                                  errmsg("malformed SCRAM message"),
    1045                 :             :                                                  errdetail("The client selected SCRAM-SHA-256 without channel binding, but the SCRAM message includes channel binding data.")));
    1046                 :             : 
    1047                 :           0 :                         channel_binding_type = read_attr_value(&p, 'p');
    1048                 :             : 
    1049                 :             :                         /*
    1050                 :             :                          * The only channel binding type we support is
    1051                 :             :                          * tls-server-end-point.
    1052                 :             :                          */
    1053         [ #  # ]:           0 :                         if (strcmp(channel_binding_type, "tls-server-end-point") != 0)
    1054   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1055                 :             :                                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1056                 :             :                                                  errmsg("unsupported SCRAM channel-binding type \"%s\"",
    1057                 :             :                                                                 sanitize_str(channel_binding_type))));
    1058                 :           0 :                         break;
    1059                 :             :                 default:
    1060   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1061                 :             :                                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1062                 :             :                                          errmsg("malformed SCRAM message"),
    1063                 :             :                                          errdetail("Unexpected channel-binding flag \"%s\".",
    1064                 :             :                                                            sanitize_char(*p))));
    1065                 :           0 :         }
    1066                 :             : 
    1067                 :             :         /*
    1068                 :             :          * Forbid optional authzid (authorization identity).  We don't support it.
    1069                 :             :          */
    1070         [ #  # ]:           0 :         if (*p == 'a')
    1071   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1072                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1073                 :             :                                  errmsg("client uses authorization identity, but it is not supported")));
    1074         [ #  # ]:           0 :         if (*p != ',')
    1075   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1076                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1077                 :             :                                  errmsg("malformed SCRAM message"),
    1078                 :             :                                  errdetail("Unexpected attribute \"%s\" in client-first-message.",
    1079                 :             :                                                    sanitize_char(*p))));
    1080                 :           0 :         p++;
    1081                 :             : 
    1082                 :           0 :         state->client_first_message_bare = pstrdup(p);
    1083                 :             : 
    1084                 :             :         /*
    1085                 :             :          * Any mandatory extensions would go here.  We don't support any.
    1086                 :             :          *
    1087                 :             :          * RFC 5802 specifies error code "e=extensions-not-supported" for this,
    1088                 :             :          * but it can only be sent in the server-final message.  We prefer to fail
    1089                 :             :          * immediately (which the RFC also allows).
    1090                 :             :          */
    1091         [ #  # ]:           0 :         if (*p == 'm')
    1092   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1093                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1094                 :             :                                  errmsg("client requires an unsupported SCRAM extension")));
    1095                 :             : 
    1096                 :             :         /*
    1097                 :             :          * Read username.  Note: this is ignored.  We use the username from the
    1098                 :             :          * startup message instead, still it is kept around if provided as it
    1099                 :             :          * proves to be useful for debugging purposes.
    1100                 :             :          */
    1101                 :           0 :         state->client_username = read_attr_value(&p, 'n');
    1102                 :             : 
    1103                 :             :         /* read nonce and check that it is made of only printable characters */
    1104                 :           0 :         state->client_nonce = read_attr_value(&p, 'r');
    1105         [ #  # ]:           0 :         if (!is_scram_printable(state->client_nonce))
    1106   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1107                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1108                 :             :                                  errmsg("non-printable characters in SCRAM nonce")));
    1109                 :             : 
    1110                 :             :         /*
    1111                 :             :          * There can be any number of optional extensions after this.  We don't
    1112                 :             :          * support any extensions, so ignore them.
    1113                 :             :          */
    1114         [ #  # ]:           0 :         while (*p != '\0')
    1115                 :           0 :                 read_any_attr(&p, NULL);
    1116                 :             : 
    1117                 :             :         /* success! */
    1118                 :           0 : }
    1119                 :             : 
    1120                 :             : /*
    1121                 :             :  * Verify the final nonce contained in the last message received from
    1122                 :             :  * client in an exchange.
    1123                 :             :  */
    1124                 :             : static bool
    1125                 :           0 : verify_final_nonce(scram_state *state)
    1126                 :             : {
    1127                 :           0 :         int                     client_nonce_len = strlen(state->client_nonce);
    1128                 :           0 :         int                     server_nonce_len = strlen(state->server_nonce);
    1129                 :           0 :         int                     final_nonce_len = strlen(state->client_final_nonce);
    1130                 :             : 
    1131         [ #  # ]:           0 :         if (final_nonce_len != client_nonce_len + server_nonce_len)
    1132                 :           0 :                 return false;
    1133         [ #  # ]:           0 :         if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0)
    1134                 :           0 :                 return false;
    1135         [ #  # ]:           0 :         if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0)
    1136                 :           0 :                 return false;
    1137                 :             : 
    1138                 :           0 :         return true;
    1139                 :           0 : }
    1140                 :             : 
    1141                 :             : /*
    1142                 :             :  * Verify the client proof contained in the last message received from
    1143                 :             :  * client in an exchange.  Returns true if the verification is a success,
    1144                 :             :  * or false for a failure.
    1145                 :             :  */
    1146                 :             : static bool
    1147                 :           0 : verify_client_proof(scram_state *state)
    1148                 :             : {
    1149                 :           0 :         uint8           ClientSignature[SCRAM_MAX_KEY_LEN];
    1150                 :           0 :         uint8           client_StoredKey[SCRAM_MAX_KEY_LEN];
    1151                 :           0 :         pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type);
    1152                 :           0 :         int                     i;
    1153                 :           0 :         const char *errstr = NULL;
    1154                 :             : 
    1155                 :             :         /*
    1156                 :             :          * Calculate ClientSignature.  Note that we don't log directly a failure
    1157                 :             :          * here even when processing the calculations as this could involve a mock
    1158                 :             :          * authentication.
    1159                 :             :          */
    1160         [ #  # ]:           0 :         if (pg_hmac_init(ctx, state->StoredKey, state->key_length) < 0 ||
    1161                 :           0 :                 pg_hmac_update(ctx,
    1162                 :           0 :                                            (uint8 *) state->client_first_message_bare,
    1163                 :           0 :                                            strlen(state->client_first_message_bare)) < 0 ||
    1164                 :           0 :                 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
    1165                 :           0 :                 pg_hmac_update(ctx,
    1166                 :           0 :                                            (uint8 *) state->server_first_message,
    1167                 :           0 :                                            strlen(state->server_first_message)) < 0 ||
    1168                 :           0 :                 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
    1169                 :           0 :                 pg_hmac_update(ctx,
    1170                 :           0 :                                            (uint8 *) state->client_final_message_without_proof,
    1171                 :           0 :                                            strlen(state->client_final_message_without_proof)) < 0 ||
    1172                 :           0 :                 pg_hmac_final(ctx, ClientSignature, state->key_length) < 0)
    1173                 :             :         {
    1174   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not calculate client signature: %s",
    1175                 :             :                          pg_hmac_error(ctx));
    1176                 :           0 :         }
    1177                 :             : 
    1178                 :           0 :         pg_hmac_free(ctx);
    1179                 :             : 
    1180                 :             :         /* Extract the ClientKey that the client calculated from the proof */
    1181         [ #  # ]:           0 :         for (i = 0; i < state->key_length; i++)
    1182                 :           0 :                 state->ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
    1183                 :             : 
    1184                 :             :         /* Hash it one more time, and compare with StoredKey */
    1185                 :           0 :         if (scram_H(state->ClientKey, state->hash_type, state->key_length,
    1186   [ #  #  #  # ]:           0 :                                 client_StoredKey, &errstr) < 0)
    1187   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not hash stored key: %s", errstr);
    1188                 :             : 
    1189         [ #  # ]:           0 :         if (memcmp(client_StoredKey, state->StoredKey, state->key_length) != 0)
    1190                 :           0 :                 return false;
    1191                 :             : 
    1192                 :           0 :         return true;
    1193                 :           0 : }
    1194                 :             : 
    1195                 :             : /*
    1196                 :             :  * Build the first server-side message sent to the client in a SCRAM
    1197                 :             :  * communication exchange.
    1198                 :             :  */
    1199                 :             : static char *
    1200                 :           0 : build_server_first_message(scram_state *state)
    1201                 :             : {
    1202                 :             :         /*------
    1203                 :             :          * The syntax for the server-first-message is: (RFC 5802)
    1204                 :             :          *
    1205                 :             :          * server-first-message =
    1206                 :             :          *                                       [reserved-mext ","] nonce "," salt ","
    1207                 :             :          *                                       iteration-count ["," extensions]
    1208                 :             :          *
    1209                 :             :          * nonce                   = "r=" c-nonce [s-nonce]
    1210                 :             :          *                                       ;; Second part provided by server.
    1211                 :             :          *
    1212                 :             :          * c-nonce                 = printable
    1213                 :             :          *
    1214                 :             :          * s-nonce                 = printable
    1215                 :             :          *
    1216                 :             :          * salt                    = "s=" base64
    1217                 :             :          *
    1218                 :             :          * iteration-count = "i=" posit-number
    1219                 :             :          *                                       ;; A positive number.
    1220                 :             :          *
    1221                 :             :          * Example:
    1222                 :             :          *
    1223                 :             :          * r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
    1224                 :             :          *------
    1225                 :             :          */
    1226                 :             : 
    1227                 :             :         /*
    1228                 :             :          * Per the spec, the nonce may consist of any printable ASCII characters.
    1229                 :             :          * For convenience, however, we don't use the whole range available,
    1230                 :             :          * rather, we generate some random bytes, and base64 encode them.
    1231                 :             :          */
    1232                 :           0 :         uint8           raw_nonce[SCRAM_RAW_NONCE_LEN];
    1233                 :           0 :         int                     encoded_len;
    1234                 :             : 
    1235         [ #  # ]:           0 :         if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
    1236   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1237                 :             :                                 (errcode(ERRCODE_INTERNAL_ERROR),
    1238                 :             :                                  errmsg("could not generate random nonce")));
    1239                 :             : 
    1240                 :           0 :         encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
    1241                 :             :         /* don't forget the zero-terminator */
    1242                 :           0 :         state->server_nonce = palloc(encoded_len + 1);
    1243                 :           0 :         encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
    1244                 :           0 :                                                                 state->server_nonce, encoded_len);
    1245         [ #  # ]:           0 :         if (encoded_len < 0)
    1246   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1247                 :             :                                 (errcode(ERRCODE_INTERNAL_ERROR),
    1248                 :             :                                  errmsg("could not encode random nonce")));
    1249                 :           0 :         state->server_nonce[encoded_len] = '\0';
    1250                 :             : 
    1251                 :           0 :         state->server_first_message =
    1252                 :           0 :                 psprintf("r=%s%s,s=%s,i=%d",
    1253                 :           0 :                                  state->client_nonce, state->server_nonce,
    1254                 :           0 :                                  state->salt, state->iterations);
    1255                 :             : 
    1256                 :           0 :         return pstrdup(state->server_first_message);
    1257                 :           0 : }
    1258                 :             : 
    1259                 :             : 
    1260                 :             : /*
    1261                 :             :  * Read and parse the final message received from client.
    1262                 :             :  */
    1263                 :             : static void
    1264                 :           0 : read_client_final_message(scram_state *state, const char *input)
    1265                 :             : {
    1266                 :           0 :         char            attr;
    1267                 :           0 :         char       *channel_binding;
    1268                 :           0 :         char       *value;
    1269                 :           0 :         char       *begin,
    1270                 :             :                            *proof;
    1271                 :           0 :         char       *p;
    1272                 :           0 :         uint8      *client_proof;
    1273                 :           0 :         int                     client_proof_len;
    1274                 :             : 
    1275                 :           0 :         begin = p = pstrdup(input);
    1276                 :             : 
    1277                 :             :         /*------
    1278                 :             :          * The syntax for the server-first-message is: (RFC 5802)
    1279                 :             :          *
    1280                 :             :          * gs2-header      = gs2-cbind-flag "," [ authzid ] ","
    1281                 :             :          *                                       ;; GS2 header for SCRAM
    1282                 :             :          *                                       ;; (the actual GS2 header includes an optional
    1283                 :             :          *                                       ;; flag to indicate that the GSS mechanism is not
    1284                 :             :          *                                       ;; "standard", but since SCRAM is "standard", we
    1285                 :             :          *                                       ;; don't include that flag).
    1286                 :             :          *
    1287                 :             :          * cbind-input   = gs2-header [ cbind-data ]
    1288                 :             :          *                                       ;; cbind-data MUST be present for
    1289                 :             :          *                                       ;; gs2-cbind-flag of "p" and MUST be absent
    1290                 :             :          *                                       ;; for "y" or "n".
    1291                 :             :          *
    1292                 :             :          * channel-binding = "c=" base64
    1293                 :             :          *                                       ;; base64 encoding of cbind-input.
    1294                 :             :          *
    1295                 :             :          * proof                   = "p=" base64
    1296                 :             :          *
    1297                 :             :          * client-final-message-without-proof =
    1298                 :             :          *                                       channel-binding "," nonce [","
    1299                 :             :          *                                       extensions]
    1300                 :             :          *
    1301                 :             :          * client-final-message =
    1302                 :             :          *                                       client-final-message-without-proof "," proof
    1303                 :             :          *------
    1304                 :             :          */
    1305                 :             : 
    1306                 :             :         /*
    1307                 :             :          * Read channel binding.  This repeats the channel-binding flags and is
    1308                 :             :          * then followed by the actual binding data depending on the type.
    1309                 :             :          */
    1310                 :           0 :         channel_binding = read_attr_value(&p, 'c');
    1311         [ #  # ]:           0 :         if (state->channel_binding_in_use)
    1312                 :             :         {
    1313                 :             : #ifdef USE_SSL
    1314                 :           0 :                 const char *cbind_data = NULL;
    1315                 :           0 :                 size_t          cbind_data_len = 0;
    1316                 :           0 :                 size_t          cbind_header_len;
    1317                 :           0 :                 char       *cbind_input;
    1318                 :           0 :                 size_t          cbind_input_len;
    1319                 :           0 :                 char       *b64_message;
    1320                 :           0 :                 int                     b64_message_len;
    1321                 :             : 
    1322         [ #  # ]:           0 :                 Assert(state->cbind_flag == 'p');
    1323                 :             : 
    1324                 :             :                 /* Fetch hash data of server's SSL certificate */
    1325                 :           0 :                 cbind_data = be_tls_get_certificate_hash(state->port,
    1326                 :             :                                                                                                  &cbind_data_len);
    1327                 :             : 
    1328                 :             :                 /* should not happen */
    1329         [ #  # ]:           0 :                 if (cbind_data == NULL || cbind_data_len == 0)
    1330   [ #  #  #  # ]:           0 :                         elog(ERROR, "could not get server certificate hash");
    1331                 :             : 
    1332                 :           0 :                 cbind_header_len = strlen("p=tls-server-end-point,,");        /* p=type,, */
    1333                 :           0 :                 cbind_input_len = cbind_header_len + cbind_data_len;
    1334                 :           0 :                 cbind_input = palloc(cbind_input_len);
    1335                 :           0 :                 snprintf(cbind_input, cbind_input_len, "p=tls-server-end-point,,");
    1336                 :           0 :                 memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
    1337                 :             : 
    1338                 :           0 :                 b64_message_len = pg_b64_enc_len(cbind_input_len);
    1339                 :             :                 /* don't forget the zero-terminator */
    1340                 :           0 :                 b64_message = palloc(b64_message_len + 1);
    1341                 :           0 :                 b64_message_len = pg_b64_encode((uint8 *) cbind_input, cbind_input_len,
    1342                 :           0 :                                                                                 b64_message, b64_message_len);
    1343         [ #  # ]:           0 :                 if (b64_message_len < 0)
    1344   [ #  #  #  # ]:           0 :                         elog(ERROR, "could not encode channel binding data");
    1345                 :           0 :                 b64_message[b64_message_len] = '\0';
    1346                 :             : 
    1347                 :             :                 /*
    1348                 :             :                  * Compare the value sent by the client with the value expected by the
    1349                 :             :                  * server.
    1350                 :             :                  */
    1351         [ #  # ]:           0 :                 if (strcmp(channel_binding, b64_message) != 0)
    1352   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1353                 :             :                                         (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
    1354                 :             :                                          errmsg("SCRAM channel binding check failed")));
    1355                 :             : #else
    1356                 :             :                 /* shouldn't happen, because we checked this earlier already */
    1357                 :             :                 elog(ERROR, "channel binding not supported by this build");
    1358                 :             : #endif
    1359                 :           0 :         }
    1360                 :             :         else
    1361                 :             :         {
    1362                 :             :                 /*
    1363                 :             :                  * If we are not using channel binding, the binding data is expected
    1364                 :             :                  * to always be "biws", which is "n,," base64-encoded, or "eSws",
    1365                 :             :                  * which is "y,,".  We also have to check whether the flag is the same
    1366                 :             :                  * one that the client originally sent.
    1367                 :             :                  */
    1368   [ #  #  #  # ]:           0 :                 if (!(strcmp(channel_binding, "biws") == 0 && state->cbind_flag == 'n') &&
    1369         [ #  # ]:           0 :                         !(strcmp(channel_binding, "eSws") == 0 && state->cbind_flag == 'y'))
    1370   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1371                 :             :                                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1372                 :             :                                          errmsg("unexpected SCRAM channel-binding attribute in client-final-message")));
    1373                 :             :         }
    1374                 :             : 
    1375                 :           0 :         state->client_final_nonce = read_attr_value(&p, 'r');
    1376                 :             : 
    1377                 :             :         /* ignore optional extensions, read until we find "p" attribute */
    1378                 :           0 :         do
    1379                 :             :         {
    1380                 :           0 :                 proof = p - 1;
    1381                 :           0 :                 value = read_any_attr(&p, &attr);
    1382         [ #  # ]:           0 :         } while (attr != 'p');
    1383                 :             : 
    1384                 :           0 :         client_proof_len = pg_b64_dec_len(strlen(value));
    1385                 :           0 :         client_proof = palloc(client_proof_len);
    1386                 :           0 :         if (pg_b64_decode(value, strlen(value), client_proof,
    1387   [ #  #  #  # ]:           0 :                                           client_proof_len) != state->key_length)
    1388   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1389                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1390                 :             :                                  errmsg("malformed SCRAM message"),
    1391                 :             :                                  errdetail("Malformed proof in client-final-message.")));
    1392                 :           0 :         memcpy(state->ClientProof, client_proof, state->key_length);
    1393                 :           0 :         pfree(client_proof);
    1394                 :             : 
    1395         [ #  # ]:           0 :         if (*p != '\0')
    1396   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1397                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1398                 :             :                                  errmsg("malformed SCRAM message"),
    1399                 :             :                                  errdetail("Garbage found at the end of client-final-message.")));
    1400                 :             : 
    1401                 :           0 :         state->client_final_message_without_proof = palloc(proof - begin + 1);
    1402                 :           0 :         memcpy(state->client_final_message_without_proof, input, proof - begin);
    1403                 :           0 :         state->client_final_message_without_proof[proof - begin] = '\0';
    1404                 :           0 : }
    1405                 :             : 
    1406                 :             : /*
    1407                 :             :  * Build the final server-side message of an exchange.
    1408                 :             :  */
    1409                 :             : static char *
    1410                 :           0 : build_server_final_message(scram_state *state)
    1411                 :             : {
    1412                 :           0 :         uint8           ServerSignature[SCRAM_MAX_KEY_LEN];
    1413                 :           0 :         char       *server_signature_base64;
    1414                 :           0 :         int                     siglen;
    1415                 :           0 :         pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type);
    1416                 :             : 
    1417                 :             :         /* calculate ServerSignature */
    1418         [ #  # ]:           0 :         if (pg_hmac_init(ctx, state->ServerKey, state->key_length) < 0 ||
    1419                 :           0 :                 pg_hmac_update(ctx,
    1420                 :           0 :                                            (uint8 *) state->client_first_message_bare,
    1421                 :           0 :                                            strlen(state->client_first_message_bare)) < 0 ||
    1422                 :           0 :                 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
    1423                 :           0 :                 pg_hmac_update(ctx,
    1424                 :           0 :                                            (uint8 *) state->server_first_message,
    1425                 :           0 :                                            strlen(state->server_first_message)) < 0 ||
    1426                 :           0 :                 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
    1427                 :           0 :                 pg_hmac_update(ctx,
    1428                 :           0 :                                            (uint8 *) state->client_final_message_without_proof,
    1429                 :           0 :                                            strlen(state->client_final_message_without_proof)) < 0 ||
    1430                 :           0 :                 pg_hmac_final(ctx, ServerSignature, state->key_length) < 0)
    1431                 :             :         {
    1432   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not calculate server signature: %s",
    1433                 :             :                          pg_hmac_error(ctx));
    1434                 :           0 :         }
    1435                 :             : 
    1436                 :           0 :         pg_hmac_free(ctx);
    1437                 :             : 
    1438                 :           0 :         siglen = pg_b64_enc_len(state->key_length);
    1439                 :             :         /* don't forget the zero-terminator */
    1440                 :           0 :         server_signature_base64 = palloc(siglen + 1);
    1441                 :           0 :         siglen = pg_b64_encode(ServerSignature,
    1442                 :           0 :                                                    state->key_length, server_signature_base64,
    1443                 :           0 :                                                    siglen);
    1444         [ #  # ]:           0 :         if (siglen < 0)
    1445   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not encode server signature");
    1446                 :           0 :         server_signature_base64[siglen] = '\0';
    1447                 :             : 
    1448                 :             :         /*------
    1449                 :             :          * The syntax for the server-final-message is: (RFC 5802)
    1450                 :             :          *
    1451                 :             :          * verifier                = "v=" base64
    1452                 :             :          *                                       ;; base-64 encoded ServerSignature.
    1453                 :             :          *
    1454                 :             :          * server-final-message = (server-error / verifier)
    1455                 :             :          *                                       ["," extensions]
    1456                 :             :          *
    1457                 :             :          *------
    1458                 :             :          */
    1459                 :           0 :         return psprintf("v=%s", server_signature_base64);
    1460                 :           0 : }
    1461                 :             : 
    1462                 :             : 
    1463                 :             : /*
    1464                 :             :  * Deterministically generate salt for mock authentication, using a SHA256
    1465                 :             :  * hash based on the username and a cluster-level secret key.  Returns a
    1466                 :             :  * pointer to a static buffer of size SCRAM_DEFAULT_SALT_LEN, or NULL.
    1467                 :             :  */
    1468                 :             : static uint8 *
    1469                 :           0 : scram_mock_salt(const char *username, pg_cryptohash_type hash_type,
    1470                 :             :                                 int key_length)
    1471                 :             : {
    1472                 :           0 :         pg_cryptohash_ctx *ctx;
    1473                 :             :         static uint8 sha_digest[SCRAM_MAX_KEY_LEN];
    1474                 :           0 :         char       *mock_auth_nonce = GetMockAuthenticationNonce();
    1475                 :             : 
    1476                 :             :         /*
    1477                 :             :          * Generate salt using a SHA256 hash of the username and the cluster's
    1478                 :             :          * mock authentication nonce.  (This works as long as the salt length is
    1479                 :             :          * not larger than the SHA256 digest length.  If the salt is smaller, the
    1480                 :             :          * caller will just ignore the extra data.)
    1481                 :             :          */
    1482                 :             :         StaticAssertDecl(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN,
    1483                 :             :                                          "salt length greater than SHA256 digest length");
    1484                 :             : 
    1485                 :             :         /*
    1486                 :             :          * This may be worth refreshing if support for more hash methods is\
    1487                 :             :          * added.
    1488                 :             :          */
    1489         [ #  # ]:           0 :         Assert(hash_type == PG_SHA256);
    1490                 :             : 
    1491                 :           0 :         ctx = pg_cryptohash_create(hash_type);
    1492         [ #  # ]:           0 :         if (pg_cryptohash_init(ctx) < 0 ||
    1493         [ #  # ]:           0 :                 pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
    1494   [ #  #  #  # ]:           0 :                 pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
    1495                 :           0 :                 pg_cryptohash_final(ctx, sha_digest, key_length) < 0)
    1496                 :             :         {
    1497                 :           0 :                 pg_cryptohash_free(ctx);
    1498                 :           0 :                 return NULL;
    1499                 :             :         }
    1500                 :           0 :         pg_cryptohash_free(ctx);
    1501                 :             : 
    1502                 :           0 :         return sha_digest;
    1503                 :           0 : }
        

Generated by: LCOV version 2.3.2-1