LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-auth-scram.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 0 258 0.0 %
Date: 2017-09-29 15:12:54 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * fe-auth-scram.c
       4             :  *     The front-end (client) implementation of SCRAM authentication.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/interfaces/libpq/fe-auth-scram.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : 
      15             : #include "postgres_fe.h"
      16             : 
      17             : #include "common/base64.h"
      18             : #include "common/saslprep.h"
      19             : #include "common/scram-common.h"
      20             : #include "fe-auth.h"
      21             : 
      22             : /* These are needed for getpid(), in the fallback implementation */
      23             : #ifndef HAVE_STRONG_RANDOM
      24             : #include <sys/types.h>
      25             : #include <unistd.h>
      26             : #endif
      27             : 
      28             : /*
      29             :  * Status of exchange messages used for SCRAM authentication via the
      30             :  * SASL protocol.
      31             :  */
      32             : typedef enum
      33             : {
      34             :     FE_SCRAM_INIT,
      35             :     FE_SCRAM_NONCE_SENT,
      36             :     FE_SCRAM_PROOF_SENT,
      37             :     FE_SCRAM_FINISHED
      38             : } fe_scram_state_enum;
      39             : 
      40             : typedef struct
      41             : {
      42             :     fe_scram_state_enum state;
      43             : 
      44             :     /* These are supplied by the user */
      45             :     const char *username;
      46             :     char       *password;
      47             : 
      48             :     /* We construct these */
      49             :     uint8       SaltedPassword[SCRAM_KEY_LEN];
      50             :     char       *client_nonce;
      51             :     char       *client_first_message_bare;
      52             :     char       *client_final_message_without_proof;
      53             : 
      54             :     /* These come from the server-first message */
      55             :     char       *server_first_message;
      56             :     char       *salt;
      57             :     int         saltlen;
      58             :     int         iterations;
      59             :     char       *nonce;
      60             : 
      61             :     /* These come from the server-final message */
      62             :     char       *server_final_message;
      63             :     char        ServerSignature[SCRAM_KEY_LEN];
      64             : } fe_scram_state;
      65             : 
      66             : static bool read_server_first_message(fe_scram_state *state, char *input,
      67             :                           PQExpBuffer errormessage);
      68             : static bool read_server_final_message(fe_scram_state *state, char *input,
      69             :                           PQExpBuffer errormessage);
      70             : static char *build_client_first_message(fe_scram_state *state,
      71             :                            PQExpBuffer errormessage);
      72             : static char *build_client_final_message(fe_scram_state *state,
      73             :                            PQExpBuffer errormessage);
      74             : static bool verify_server_signature(fe_scram_state *state);
      75             : static void calculate_client_proof(fe_scram_state *state,
      76             :                        const char *client_final_message_without_proof,
      77             :                        uint8 *result);
      78             : static bool pg_frontend_random(char *dst, int len);
      79             : 
      80             : /*
      81             :  * Initialize SCRAM exchange status.
      82             :  */
      83             : void *
      84           0 : pg_fe_scram_init(const char *username, const char *password)
      85             : {
      86             :     fe_scram_state *state;
      87             :     char       *prep_password;
      88             :     pg_saslprep_rc rc;
      89             : 
      90           0 :     state = (fe_scram_state *) malloc(sizeof(fe_scram_state));
      91           0 :     if (!state)
      92           0 :         return NULL;
      93           0 :     memset(state, 0, sizeof(fe_scram_state));
      94           0 :     state->state = FE_SCRAM_INIT;
      95           0 :     state->username = username;
      96             : 
      97             :     /* Normalize the password with SASLprep, if possible */
      98           0 :     rc = pg_saslprep(password, &prep_password);
      99           0 :     if (rc == SASLPREP_OOM)
     100             :     {
     101           0 :         free(state);
     102           0 :         return NULL;
     103             :     }
     104           0 :     if (rc != SASLPREP_SUCCESS)
     105             :     {
     106           0 :         prep_password = strdup(password);
     107           0 :         if (!prep_password)
     108             :         {
     109           0 :             free(state);
     110           0 :             return NULL;
     111             :         }
     112             :     }
     113           0 :     state->password = prep_password;
     114             : 
     115           0 :     return state;
     116             : }
     117             : 
     118             : /*
     119             :  * Free SCRAM exchange status
     120             :  */
     121             : void
     122           0 : pg_fe_scram_free(void *opaq)
     123             : {
     124           0 :     fe_scram_state *state = (fe_scram_state *) opaq;
     125             : 
     126           0 :     if (state->password)
     127           0 :         free(state->password);
     128             : 
     129             :     /* client messages */
     130           0 :     if (state->client_nonce)
     131           0 :         free(state->client_nonce);
     132           0 :     if (state->client_first_message_bare)
     133           0 :         free(state->client_first_message_bare);
     134           0 :     if (state->client_final_message_without_proof)
     135           0 :         free(state->client_final_message_without_proof);
     136             : 
     137             :     /* first message from server */
     138           0 :     if (state->server_first_message)
     139           0 :         free(state->server_first_message);
     140           0 :     if (state->salt)
     141           0 :         free(state->salt);
     142           0 :     if (state->nonce)
     143           0 :         free(state->nonce);
     144             : 
     145             :     /* final message from server */
     146           0 :     if (state->server_final_message)
     147           0 :         free(state->server_final_message);
     148             : 
     149           0 :     free(state);
     150           0 : }
     151             : 
     152             : /*
     153             :  * Exchange a SCRAM message with backend.
     154             :  */
     155             : void
     156           0 : pg_fe_scram_exchange(void *opaq, char *input, int inputlen,
     157             :                      char **output, int *outputlen,
     158             :                      bool *done, bool *success, PQExpBuffer errorMessage)
     159             : {
     160           0 :     fe_scram_state *state = (fe_scram_state *) opaq;
     161             : 
     162           0 :     *done = false;
     163           0 :     *success = false;
     164           0 :     *output = NULL;
     165           0 :     *outputlen = 0;
     166             : 
     167             :     /*
     168             :      * Check that the input length agrees with the string length of the input.
     169             :      * We can ignore inputlen after this.
     170             :      */
     171           0 :     if (state->state != FE_SCRAM_INIT)
     172             :     {
     173           0 :         if (inputlen == 0)
     174             :         {
     175           0 :             printfPQExpBuffer(errorMessage,
     176             :                               libpq_gettext("malformed SCRAM message (empty message)\n"));
     177           0 :             goto error;
     178             :         }
     179           0 :         if (inputlen != strlen(input))
     180             :         {
     181           0 :             printfPQExpBuffer(errorMessage,
     182             :                               libpq_gettext("malformed SCRAM message (length mismatch)\n"));
     183           0 :             goto error;
     184             :         }
     185             :     }
     186             : 
     187           0 :     switch (state->state)
     188             :     {
     189             :         case FE_SCRAM_INIT:
     190             :             /* Begin the SCRAM handshake, by sending client nonce */
     191           0 :             *output = build_client_first_message(state, errorMessage);
     192           0 :             if (*output == NULL)
     193           0 :                 goto error;
     194             : 
     195           0 :             *outputlen = strlen(*output);
     196           0 :             *done = false;
     197           0 :             state->state = FE_SCRAM_NONCE_SENT;
     198           0 :             break;
     199             : 
     200             :         case FE_SCRAM_NONCE_SENT:
     201             :             /* Receive salt and server nonce, send response. */
     202           0 :             if (!read_server_first_message(state, input, errorMessage))
     203           0 :                 goto error;
     204             : 
     205           0 :             *output = build_client_final_message(state, errorMessage);
     206           0 :             if (*output == NULL)
     207           0 :                 goto error;
     208             : 
     209           0 :             *outputlen = strlen(*output);
     210           0 :             *done = false;
     211           0 :             state->state = FE_SCRAM_PROOF_SENT;
     212           0 :             break;
     213             : 
     214             :         case FE_SCRAM_PROOF_SENT:
     215             :             /* Receive server signature */
     216           0 :             if (!read_server_final_message(state, input, errorMessage))
     217           0 :                 goto error;
     218             : 
     219             :             /*
     220             :              * Verify server signature, to make sure we're talking to the
     221             :              * genuine server.  XXX: A fake server could simply not require
     222             :              * authentication, though.  There is currently no option in libpq
     223             :              * to reject a connection, if SCRAM authentication did not happen.
     224             :              */
     225           0 :             if (verify_server_signature(state))
     226           0 :                 *success = true;
     227             :             else
     228             :             {
     229           0 :                 *success = false;
     230           0 :                 printfPQExpBuffer(errorMessage,
     231             :                                   libpq_gettext("incorrect server signature\n"));
     232             :             }
     233           0 :             *done = true;
     234           0 :             state->state = FE_SCRAM_FINISHED;
     235           0 :             break;
     236             : 
     237             :         default:
     238             :             /* shouldn't happen */
     239           0 :             printfPQExpBuffer(errorMessage,
     240             :                               libpq_gettext("invalid SCRAM exchange state\n"));
     241           0 :             goto error;
     242             :     }
     243           0 :     return;
     244             : 
     245             : error:
     246           0 :     *done = true;
     247           0 :     *success = false;
     248           0 :     return;
     249             : }
     250             : 
     251             : /*
     252             :  * Read value for an attribute part of a SCRAM message.
     253             :  */
     254             : static char *
     255           0 : read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
     256             : {
     257           0 :     char       *begin = *input;
     258             :     char       *end;
     259             : 
     260           0 :     if (*begin != attr)
     261             :     {
     262           0 :         printfPQExpBuffer(errorMessage,
     263             :                           libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"),
     264             :                           attr);
     265           0 :         return NULL;
     266             :     }
     267           0 :     begin++;
     268             : 
     269           0 :     if (*begin != '=')
     270             :     {
     271           0 :         printfPQExpBuffer(errorMessage,
     272             :                           libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"),
     273             :                           attr);
     274           0 :         return NULL;
     275             :     }
     276           0 :     begin++;
     277             : 
     278           0 :     end = begin;
     279           0 :     while (*end && *end != ',')
     280           0 :         end++;
     281             : 
     282           0 :     if (*end)
     283             :     {
     284           0 :         *end = '\0';
     285           0 :         *input = end + 1;
     286             :     }
     287             :     else
     288           0 :         *input = end;
     289             : 
     290           0 :     return begin;
     291             : }
     292             : 
     293             : /*
     294             :  * Build the first exchange message sent by the client.
     295             :  */
     296             : static char *
     297           0 : build_client_first_message(fe_scram_state *state, PQExpBuffer errormessage)
     298             : {
     299             :     char        raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
     300             :     char       *buf;
     301             :     char        buflen;
     302             :     int         encoded_len;
     303             : 
     304             :     /*
     305             :      * Generate a "raw" nonce.  This is converted to ASCII-printable form by
     306             :      * base64-encoding it.
     307             :      */
     308           0 :     if (!pg_frontend_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
     309             :     {
     310           0 :         printfPQExpBuffer(errormessage,
     311             :                           libpq_gettext("could not generate nonce\n"));
     312           0 :         return NULL;
     313             :     }
     314             : 
     315           0 :     state->client_nonce = malloc(pg_b64_enc_len(SCRAM_RAW_NONCE_LEN) + 1);
     316           0 :     if (state->client_nonce == NULL)
     317             :     {
     318           0 :         printfPQExpBuffer(errormessage,
     319             :                           libpq_gettext("out of memory\n"));
     320           0 :         return NULL;
     321             :     }
     322           0 :     encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN, state->client_nonce);
     323           0 :     state->client_nonce[encoded_len] = '\0';
     324             : 
     325             :     /*
     326             :      * Generate message.  The username is left empty as the backend uses the
     327             :      * value provided by the startup packet.  Also, as this username is not
     328             :      * prepared with SASLprep, the message parsing would fail if it includes
     329             :      * '=' or ',' characters.
     330             :      */
     331           0 :     buflen = 8 + strlen(state->client_nonce) + 1;
     332           0 :     buf = malloc(buflen);
     333           0 :     if (buf == NULL)
     334             :     {
     335           0 :         printfPQExpBuffer(errormessage,
     336             :                           libpq_gettext("out of memory\n"));
     337           0 :         return NULL;
     338             :     }
     339           0 :     snprintf(buf, buflen, "n,,n=,r=%s", state->client_nonce);
     340             : 
     341           0 :     state->client_first_message_bare = strdup(buf + 3);
     342           0 :     if (!state->client_first_message_bare)
     343             :     {
     344           0 :         free(buf);
     345           0 :         printfPQExpBuffer(errormessage,
     346             :                           libpq_gettext("out of memory\n"));
     347           0 :         return NULL;
     348             :     }
     349             : 
     350           0 :     return buf;
     351             : }
     352             : 
     353             : /*
     354             :  * Build the final exchange message sent from the client.
     355             :  */
     356             : static char *
     357           0 : build_client_final_message(fe_scram_state *state, PQExpBuffer errormessage)
     358             : {
     359             :     PQExpBufferData buf;
     360             :     uint8       client_proof[SCRAM_KEY_LEN];
     361             :     char       *result;
     362             : 
     363           0 :     initPQExpBuffer(&buf);
     364             : 
     365             :     /*
     366             :      * Construct client-final-message-without-proof.  We need to remember it
     367             :      * for verifying the server proof in the final step of authentication.
     368             :      */
     369           0 :     appendPQExpBuffer(&buf, "c=biws,r=%s", state->nonce);
     370           0 :     if (PQExpBufferDataBroken(buf))
     371           0 :         goto oom_error;
     372             : 
     373           0 :     state->client_final_message_without_proof = strdup(buf.data);
     374           0 :     if (state->client_final_message_without_proof == NULL)
     375           0 :         goto oom_error;
     376             : 
     377             :     /* Append proof to it, to form client-final-message. */
     378           0 :     calculate_client_proof(state,
     379           0 :                            state->client_final_message_without_proof,
     380             :                            client_proof);
     381             : 
     382           0 :     appendPQExpBuffer(&buf, ",p=");
     383           0 :     if (!enlargePQExpBuffer(&buf, pg_b64_enc_len(SCRAM_KEY_LEN)))
     384           0 :         goto oom_error;
     385           0 :     buf.len += pg_b64_encode((char *) client_proof,
     386             :                              SCRAM_KEY_LEN,
     387           0 :                              buf.data + buf.len);
     388           0 :     buf.data[buf.len] = '\0';
     389             : 
     390           0 :     result = strdup(buf.data);
     391           0 :     if (result == NULL)
     392           0 :         goto oom_error;
     393             : 
     394           0 :     termPQExpBuffer(&buf);
     395           0 :     return result;
     396             : 
     397             : oom_error:
     398           0 :     termPQExpBuffer(&buf);
     399           0 :     printfPQExpBuffer(errormessage,
     400             :                       libpq_gettext("out of memory\n"));
     401           0 :     return NULL;
     402             : }
     403             : 
     404             : /*
     405             :  * Read the first exchange message coming from the server.
     406             :  */
     407             : static bool
     408           0 : read_server_first_message(fe_scram_state *state, char *input,
     409             :                           PQExpBuffer errormessage)
     410             : {
     411             :     char       *iterations_str;
     412             :     char       *endptr;
     413             :     char       *encoded_salt;
     414             :     char       *nonce;
     415             : 
     416           0 :     state->server_first_message = strdup(input);
     417           0 :     if (state->server_first_message == NULL)
     418             :     {
     419           0 :         printfPQExpBuffer(errormessage,
     420             :                           libpq_gettext("out of memory\n"));
     421           0 :         return false;
     422             :     }
     423             : 
     424             :     /* parse the message */
     425           0 :     nonce = read_attr_value(&input, 'r', errormessage);
     426           0 :     if (nonce == NULL)
     427             :     {
     428             :         /* read_attr_value() has generated an error string */
     429           0 :         return false;
     430             :     }
     431             : 
     432             :     /* Verify immediately that the server used our part of the nonce */
     433           0 :     if (strlen(nonce) < strlen(state->client_nonce) ||
     434           0 :         memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
     435             :     {
     436           0 :         printfPQExpBuffer(errormessage,
     437             :                           libpq_gettext("invalid SCRAM response (nonce mismatch)\n"));
     438           0 :         return false;
     439             :     }
     440             : 
     441           0 :     state->nonce = strdup(nonce);
     442           0 :     if (state->nonce == NULL)
     443             :     {
     444           0 :         printfPQExpBuffer(errormessage,
     445             :                           libpq_gettext("out of memory\n"));
     446           0 :         return false;
     447             :     }
     448             : 
     449           0 :     encoded_salt = read_attr_value(&input, 's', errormessage);
     450           0 :     if (encoded_salt == NULL)
     451             :     {
     452             :         /* read_attr_value() has generated an error string */
     453           0 :         return false;
     454             :     }
     455           0 :     state->salt = malloc(pg_b64_dec_len(strlen(encoded_salt)));
     456           0 :     if (state->salt == NULL)
     457             :     {
     458           0 :         printfPQExpBuffer(errormessage,
     459             :                           libpq_gettext("out of memory\n"));
     460           0 :         return false;
     461             :     }
     462           0 :     state->saltlen = pg_b64_decode(encoded_salt,
     463           0 :                                    strlen(encoded_salt),
     464             :                                    state->salt);
     465             : 
     466           0 :     iterations_str = read_attr_value(&input, 'i', errormessage);
     467           0 :     if (iterations_str == NULL)
     468             :     {
     469             :         /* read_attr_value() has generated an error string */
     470           0 :         return false;
     471             :     }
     472           0 :     state->iterations = strtol(iterations_str, &endptr, 10);
     473           0 :     if (*endptr != '\0' || state->iterations < 1)
     474             :     {
     475           0 :         printfPQExpBuffer(errormessage,
     476             :                           libpq_gettext("malformed SCRAM message (invalid iteration count)\n"));
     477           0 :         return false;
     478             :     }
     479             : 
     480           0 :     if (*input != '\0')
     481           0 :         printfPQExpBuffer(errormessage,
     482             :                           libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n"));
     483             : 
     484           0 :     return true;
     485             : }
     486             : 
     487             : /*
     488             :  * Read the final exchange message coming from the server.
     489             :  */
     490             : static bool
     491           0 : read_server_final_message(fe_scram_state *state, char *input,
     492             :                           PQExpBuffer errormessage)
     493             : {
     494             :     char       *encoded_server_signature;
     495             :     int         server_signature_len;
     496             : 
     497           0 :     state->server_final_message = strdup(input);
     498           0 :     if (!state->server_final_message)
     499             :     {
     500           0 :         printfPQExpBuffer(errormessage,
     501             :                           libpq_gettext("out of memory\n"));
     502           0 :         return false;
     503             :     }
     504             : 
     505             :     /* Check for error result. */
     506           0 :     if (*input == 'e')
     507             :     {
     508           0 :         char       *errmsg = read_attr_value(&input, 'e', errormessage);
     509             : 
     510           0 :         printfPQExpBuffer(errormessage,
     511             :                           libpq_gettext("error received from server in SCRAM exchange: %s\n"),
     512             :                           errmsg);
     513           0 :         return false;
     514             :     }
     515             : 
     516             :     /* Parse the message. */
     517           0 :     encoded_server_signature = read_attr_value(&input, 'v', errormessage);
     518           0 :     if (encoded_server_signature == NULL)
     519             :     {
     520             :         /* read_attr_value() has generated an error message */
     521           0 :         return false;
     522             :     }
     523             : 
     524           0 :     if (*input != '\0')
     525           0 :         printfPQExpBuffer(errormessage,
     526             :                           libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
     527             : 
     528           0 :     server_signature_len = pg_b64_decode(encoded_server_signature,
     529           0 :                                          strlen(encoded_server_signature),
     530           0 :                                          state->ServerSignature);
     531           0 :     if (server_signature_len != SCRAM_KEY_LEN)
     532             :     {
     533           0 :         printfPQExpBuffer(errormessage,
     534             :                           libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
     535           0 :         return false;
     536             :     }
     537             : 
     538           0 :     return true;
     539             : }
     540             : 
     541             : /*
     542             :  * Calculate the client proof, part of the final exchange message sent
     543             :  * by the client.
     544             :  */
     545             : static void
     546           0 : calculate_client_proof(fe_scram_state *state,
     547             :                        const char *client_final_message_without_proof,
     548             :                        uint8 *result)
     549             : {
     550             :     uint8       StoredKey[SCRAM_KEY_LEN];
     551             :     uint8       ClientKey[SCRAM_KEY_LEN];
     552             :     uint8       ClientSignature[SCRAM_KEY_LEN];
     553             :     int         i;
     554             :     scram_HMAC_ctx ctx;
     555             : 
     556             :     /*
     557             :      * Calculate SaltedPassword, and store it in 'state' so that we can reuse
     558             :      * it later in verify_server_signature.
     559             :      */
     560           0 :     scram_SaltedPassword(state->password, state->salt, state->saltlen,
     561           0 :                          state->iterations, state->SaltedPassword);
     562             : 
     563           0 :     scram_ClientKey(state->SaltedPassword, ClientKey);
     564           0 :     scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey);
     565             : 
     566           0 :     scram_HMAC_init(&ctx, StoredKey, SCRAM_KEY_LEN);
     567           0 :     scram_HMAC_update(&ctx,
     568           0 :                       state->client_first_message_bare,
     569           0 :                       strlen(state->client_first_message_bare));
     570           0 :     scram_HMAC_update(&ctx, ",", 1);
     571           0 :     scram_HMAC_update(&ctx,
     572           0 :                       state->server_first_message,
     573           0 :                       strlen(state->server_first_message));
     574           0 :     scram_HMAC_update(&ctx, ",", 1);
     575           0 :     scram_HMAC_update(&ctx,
     576             :                       client_final_message_without_proof,
     577           0 :                       strlen(client_final_message_without_proof));
     578           0 :     scram_HMAC_final(ClientSignature, &ctx);
     579             : 
     580           0 :     for (i = 0; i < SCRAM_KEY_LEN; i++)
     581           0 :         result[i] = ClientKey[i] ^ ClientSignature[i];
     582           0 : }
     583             : 
     584             : /*
     585             :  * Validate the server signature, received as part of the final exchange
     586             :  * message received from the server.
     587             :  */
     588             : static bool
     589           0 : verify_server_signature(fe_scram_state *state)
     590             : {
     591             :     uint8       expected_ServerSignature[SCRAM_KEY_LEN];
     592             :     uint8       ServerKey[SCRAM_KEY_LEN];
     593             :     scram_HMAC_ctx ctx;
     594             : 
     595           0 :     scram_ServerKey(state->SaltedPassword, ServerKey);
     596             : 
     597             :     /* calculate ServerSignature */
     598           0 :     scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN);
     599           0 :     scram_HMAC_update(&ctx,
     600           0 :                       state->client_first_message_bare,
     601           0 :                       strlen(state->client_first_message_bare));
     602           0 :     scram_HMAC_update(&ctx, ",", 1);
     603           0 :     scram_HMAC_update(&ctx,
     604           0 :                       state->server_first_message,
     605           0 :                       strlen(state->server_first_message));
     606           0 :     scram_HMAC_update(&ctx, ",", 1);
     607           0 :     scram_HMAC_update(&ctx,
     608           0 :                       state->client_final_message_without_proof,
     609           0 :                       strlen(state->client_final_message_without_proof));
     610           0 :     scram_HMAC_final(expected_ServerSignature, &ctx);
     611             : 
     612           0 :     if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
     613           0 :         return false;
     614             : 
     615           0 :     return true;
     616             : }
     617             : 
     618             : /*
     619             :  * Build a new SCRAM verifier.
     620             :  */
     621             : char *
     622           0 : pg_fe_scram_build_verifier(const char *password)
     623             : {
     624           0 :     char       *prep_password = NULL;
     625             :     pg_saslprep_rc rc;
     626             :     char        saltbuf[SCRAM_DEFAULT_SALT_LEN];
     627             :     char       *result;
     628             : 
     629             :     /*
     630             :      * Normalize the password with SASLprep.  If that doesn't work, because
     631             :      * the password isn't valid UTF-8 or contains prohibited characters, just
     632             :      * proceed with the original password.  (See comments at top of file.)
     633             :      */
     634           0 :     rc = pg_saslprep(password, &prep_password);
     635           0 :     if (rc == SASLPREP_OOM)
     636           0 :         return NULL;
     637           0 :     if (rc == SASLPREP_SUCCESS)
     638           0 :         password = (const char *) prep_password;
     639             : 
     640             :     /* Generate a random salt */
     641           0 :     if (!pg_frontend_random(saltbuf, SCRAM_DEFAULT_SALT_LEN))
     642             :     {
     643           0 :         if (prep_password)
     644           0 :             free(prep_password);
     645           0 :         return NULL;
     646             :     }
     647             : 
     648           0 :     result = scram_build_verifier(saltbuf, SCRAM_DEFAULT_SALT_LEN,
     649             :                                   SCRAM_DEFAULT_ITERATIONS, password);
     650             : 
     651           0 :     if (prep_password)
     652           0 :         free(prep_password);
     653             : 
     654           0 :     return result;
     655             : }
     656             : 
     657             : /*
     658             :  * Random number generator.
     659             :  */
     660             : static bool
     661           0 : pg_frontend_random(char *dst, int len)
     662             : {
     663             : #ifdef HAVE_STRONG_RANDOM
     664           0 :     return pg_strong_random(dst, len);
     665             : #else
     666             :     int         i;
     667             :     char       *end = dst + len;
     668             : 
     669             :     static unsigned short seed[3];
     670             :     static int  mypid = 0;
     671             : 
     672             :     pglock_thread();
     673             : 
     674             :     if (mypid != getpid())
     675             :     {
     676             :         struct timeval now;
     677             : 
     678             :         gettimeofday(&now, NULL);
     679             : 
     680             :         seed[0] = now.tv_sec ^ getpid();
     681             :         seed[1] = (unsigned short) (now.tv_usec);
     682             :         seed[2] = (unsigned short) (now.tv_usec >> 16);
     683             :     }
     684             : 
     685             :     for (i = 0; dst < end; i++)
     686             :     {
     687             :         uint32      r;
     688             :         int         j;
     689             : 
     690             :         /*
     691             :          * pg_jrand48 returns a 32-bit integer.  Fill the next 4 bytes from
     692             :          * it.
     693             :          */
     694             :         r = (uint32) pg_jrand48(seed);
     695             : 
     696             :         for (j = 0; j < 4 && dst < end; j++)
     697             :         {
     698             :             *(dst++) = (char) (r & 0xFF);
     699             :             r >>= 8;
     700             :         }
     701             :     }
     702             : 
     703             :     pgunlock_thread();
     704             : 
     705             :     return true;
     706             : #endif
     707             : }

Generated by: LCOV version 1.11