LCOV - differential code coverage report
Current view: top level - src/common - scram-common.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 66.4 % 116 77 15 17 7 7 25 32 13 21 40 4 9
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 5 5 5 2 2
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (60,120] days: 100.0 % 31 31 31
(240..) days: 53.6 % 84 45 15 17 7 7 25 13 20 36
Function coverage date bins:
(60,120] days: 100.0 % 4 4 4
(240..) days: 33.3 % 3 1 1 2

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  * scram-common.c
                                  3                 :  *      Shared frontend/backend code for SCRAM authentication
                                  4                 :  *
                                  5                 :  * This contains the common low-level functions needed in both frontend and
                                  6                 :  * backend, for implement the Salted Challenge Response Authentication
                                  7                 :  * Mechanism (SCRAM), per IETF's RFC 5802.
                                  8                 :  *
                                  9                 :  * Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group
                                 10                 :  *
                                 11                 :  * IDENTIFICATION
                                 12                 :  *    src/common/scram-common.c
                                 13                 :  *
                                 14                 :  *-------------------------------------------------------------------------
                                 15                 :  */
                                 16                 : #ifndef FRONTEND
                                 17                 : #include "postgres.h"
                                 18                 : #else
                                 19                 : #include "postgres_fe.h"
                                 20                 : #endif
                                 21                 : 
                                 22                 : #include "common/base64.h"
                                 23                 : #include "common/hmac.h"
                                 24                 : #include "common/scram-common.h"
                                 25                 : #include "port/pg_bswap.h"
                                 26                 : 
                                 27                 : /*
                                 28                 :  * Calculate SaltedPassword.
                                 29                 :  *
                                 30                 :  * The password should already be normalized by SASLprep.  Returns 0 on
                                 31                 :  * success, -1 on failure with *errstr pointing to a message about the
                                 32                 :  * error details.
                                 33                 :  */
                                 34                 : int
 2172 heikki.linnakangas         35 CBC          92 : scram_SaltedPassword(const char *password,
                                 36                 :                      pg_cryptohash_type hash_type, int key_length,
                                 37                 :                      const char *salt, int saltlen, int iterations,
                                 38                 :                      uint8 *result, const char **errstr)
                                 39                 : {
 2172 heikki.linnakangas         40 GIC          92 :     int         password_len = strlen(password);
 2016 andres                     41 CBC          92 :     uint32      one = pg_hton32(1);
 2224 heikki.linnakangas         42 ECB             :     int         i,
                                 43                 :                 j;
                                 44                 :     uint8       Ui[SCRAM_MAX_KEY_LEN];
                                 45                 :     uint8       Ui_prev[SCRAM_MAX_KEY_LEN];
  110 michael                    46 GNC          92 :     pg_hmac_ctx *hmac_ctx = pg_hmac_create(hash_type);
  736 michael                    47 ECB             : 
  736 michael                    48 GIC          92 :     if (hmac_ctx == NULL)
  451 michael                    49 ECB             :     {
  451 michael                    50 UIC           0 :         *errstr = pg_hmac_error(NULL);  /* returns OOM */
  736 michael                    51 UBC           0 :         return -1;
  451 michael                    52 EUB             :     }
                                 53                 : 
                                 54                 :     /*
                                 55                 :      * Iterate hash calculation of HMAC entry using given salt.  This is
                                 56                 :      * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom
                                 57                 :      * function.
                                 58                 :      */
                                 59                 : 
                                 60                 :     /* First iteration */
  736 michael                    61 GIC         184 :     if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 ||
  736 michael                    62 CBC         184 :         pg_hmac_update(hmac_ctx, (uint8 *) salt, saltlen) < 0 ||
                                 63             184 :         pg_hmac_update(hmac_ctx, (uint8 *) &one, sizeof(uint32)) < 0 ||
  110 michael                    64 GNC          92 :         pg_hmac_final(hmac_ctx, Ui_prev, key_length) < 0)
  858 michael                    65 ECB             :     {
  451 michael                    66 UIC           0 :         *errstr = pg_hmac_error(hmac_ctx);
  736 michael                    67 UBC           0 :         pg_hmac_free(hmac_ctx);
  858                            68               0 :         return -1;
  858 michael                    69 EUB             :     }
                                 70                 : 
  110 michael                    71 GNC          92 :     memcpy(result, Ui_prev, key_length);
 2224 heikki.linnakangas         72 ECB             : 
                                 73                 :     /* Subsequent iterations */
 2224 heikki.linnakangas         74 GIC      333950 :     for (i = 2; i <= iterations; i++)
 2224 heikki.linnakangas         75 ECB             :     {
  736 michael                    76 GIC      667716 :         if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 ||
  110 michael                    77 GNC      667716 :             pg_hmac_update(hmac_ctx, (uint8 *) Ui_prev, key_length) < 0 ||
                                 78          333858 :             pg_hmac_final(hmac_ctx, Ui, key_length) < 0)
  858 michael                    79 ECB             :         {
  451 michael                    80 UIC           0 :             *errstr = pg_hmac_error(hmac_ctx);
  736 michael                    81 UBC           0 :             pg_hmac_free(hmac_ctx);
  858                            82               0 :             return -1;
  858 michael                    83 EUB             :         }
                                 84                 : 
  110 michael                    85 GNC    11017314 :         for (j = 0; j < key_length; j++)
 2224 heikki.linnakangas         86 CBC    10683456 :             result[j] ^= Ui[j];
  110 michael                    87 GNC      333858 :         memcpy(Ui_prev, Ui, key_length);
 2224 heikki.linnakangas         88 ECB             :     }
                                 89                 : 
  736 michael                    90 GIC          92 :     pg_hmac_free(hmac_ctx);
  858 michael                    91 CBC          92 :     return 0;
 2224 heikki.linnakangas         92 ECB             : }
                                 93                 : 
                                 94                 : 
                                 95                 : /*
                                 96                 :  * Calculate hash for a NULL-terminated string. (The NULL terminator is
                                 97                 :  * not included in the hash).  Returns 0 on success, -1 on failure with *errstr
                                 98                 :  * pointing to a message about the error details.
                                 99                 :  */
                                100                 : int
  110 michael                   101 GNC         110 : scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length,
                                102                 :         uint8 *result, const char **errstr)
 2224 heikki.linnakangas        103 ECB             : {
                                104                 :     pg_cryptohash_ctx *ctx;
                                105                 : 
  110 michael                   106 GNC         110 :     ctx = pg_cryptohash_create(hash_type);
  858 michael                   107 GIC         110 :     if (ctx == NULL)
  451 michael                   108 ECB             :     {
  451 michael                   109 LBC           0 :         *errstr = pg_cryptohash_error(NULL);    /* returns OOM */
  858 michael                   110 UIC           0 :         return -1;
  451 michael                   111 EUB             :     }
  858                           112                 : 
  858 michael                   113 GIC         220 :     if (pg_cryptohash_init(ctx) < 0 ||
  110 michael                   114 GNC         220 :         pg_cryptohash_update(ctx, input, key_length) < 0 ||
                                115             110 :         pg_cryptohash_final(ctx, result, key_length) < 0)
  858 michael                   116 ECB             :     {
  451 michael                   117 LBC           0 :         *errstr = pg_cryptohash_error(ctx);
  858 michael                   118 UIC           0 :         pg_cryptohash_free(ctx);
  858 michael                   119 UBC           0 :         return -1;
  858 michael                   120 EUB             :     }
                                121                 : 
  858 michael                   122 GIC         110 :     pg_cryptohash_free(ctx);
                                123             110 :     return 0;
 2224 heikki.linnakangas        124 ECB             : }
                                125                 : 
                                126                 : /*
                                127                 :  * Calculate ClientKey.  Returns 0 on success, -1 on failure with *errstr
                                128                 :  * pointing to a message about the error details.
                                129                 :  */
                                130                 : int
  110 michael                   131 GNC          77 : scram_ClientKey(const uint8 *salted_password,
                                132                 :                 pg_cryptohash_type hash_type, int key_length,
                                133                 :                 uint8 *result, const char **errstr)
 2172 heikki.linnakangas        134 ECB             : {
  110 michael                   135 GNC          77 :     pg_hmac_ctx *ctx = pg_hmac_create(hash_type);
                                136                 : 
  736 michael                   137 GIC          77 :     if (ctx == NULL)
  451 michael                   138 ECB             :     {
  451 michael                   139 UIC           0 :         *errstr = pg_hmac_error(NULL);  /* returns OOM */
  736 michael                   140 LBC           0 :         return -1;
                                141                 :     }
 2172 heikki.linnakangas        142 EUB             : 
  110 michael                   143 GNC         154 :     if (pg_hmac_init(ctx, salted_password, key_length) < 0 ||
  736 michael                   144 GIC         154 :         pg_hmac_update(ctx, (uint8 *) "Client Key", strlen("Client Key")) < 0 ||
  110 michael                   145 GNC          77 :         pg_hmac_final(ctx, result, key_length) < 0)
  858 michael                   146 ECB             :     {
  451 michael                   147 LBC           0 :         *errstr = pg_hmac_error(ctx);
  736                           148               0 :         pg_hmac_free(ctx);
  858 michael                   149 UIC           0 :         return -1;
  858 michael                   150 EUB             :     }
                                151                 : 
  736 michael                   152 GBC          77 :     pg_hmac_free(ctx);
  858 michael                   153 GIC          77 :     return 0;
                                154                 : }
 2172 heikki.linnakangas        155 ECB             : 
                                156                 : /*
                                157                 :  * Calculate ServerKey.  Returns 0 on success, -1 on failure with *errstr
                                158                 :  * pointing to a message about the error details.
                                159                 :  */
                                160                 : int
  110 michael                   161 GNC          86 : scram_ServerKey(const uint8 *salted_password,
                                162                 :                 pg_cryptohash_type hash_type, int key_length,
                                163                 :                 uint8 *result, const char **errstr)
                                164                 : {
                                165              86 :     pg_hmac_ctx *ctx = pg_hmac_create(hash_type);
                                166                 : 
  736 michael                   167 GIC          86 :     if (ctx == NULL)
                                168                 :     {
  451 michael                   169 LBC           0 :         *errstr = pg_hmac_error(NULL);  /* returns OOM */
  736 michael                   170 UIC           0 :         return -1;
  451 michael                   171 ECB             :     }
                                172                 : 
  110 michael                   173 GNC         172 :     if (pg_hmac_init(ctx, salted_password, key_length) < 0 ||
  736 michael                   174 GBC         172 :         pg_hmac_update(ctx, (uint8 *) "Server Key", strlen("Server Key")) < 0 ||
  110 michael                   175 GNC          86 :         pg_hmac_final(ctx, result, key_length) < 0)
                                176                 :     {
  451 michael                   177 LBC           0 :         *errstr = pg_hmac_error(ctx);
  736                           178               0 :         pg_hmac_free(ctx);
  858                           179               0 :         return -1;
                                180                 :     }
  858 michael                   181 EUB             : 
  736 michael                   182 GBC          86 :     pg_hmac_free(ctx);
  858                           183              86 :     return 0;
                                184                 : }
                                185                 : 
 2167 heikki.linnakangas        186 ECB             : 
                                187                 : /*
                                188                 :  * Construct a SCRAM secret, for storing in pg_authid.rolpassword.
                                189                 :  *
                                190                 :  * The password should already have been processed with SASLprep, if necessary!
                                191                 :  *
                                192                 :  * If iterations is 0, default number of iterations is used.  The result is
                                193                 :  * palloc'd or malloc'd, so caller is responsible for freeing it.
                                194                 :  *
                                195                 :  * On error, returns NULL and sets *errstr to point to a message about the
                                196                 :  * error details.
                                197                 :  */
                                198                 : char *
  110 michael                   199 GNC          43 : scram_build_secret(pg_cryptohash_type hash_type, int key_length,
                                200                 :                    const char *salt, int saltlen, int iterations,
                                201                 :                    const char *password, const char **errstr)
                                202                 : {
                                203                 :     uint8       salted_password[SCRAM_MAX_KEY_LEN];
                                204                 :     uint8       stored_key[SCRAM_MAX_KEY_LEN];
                                205                 :     uint8       server_key[SCRAM_MAX_KEY_LEN];
                                206                 :     char       *result;
                                207                 :     char       *p;
                                208                 :     int         maxlen;
                                209                 :     int         encoded_salt_len;
                                210                 :     int         encoded_stored_len;
                                211                 :     int         encoded_server_len;
                                212                 :     int         encoded_result;
                                213                 : 
                                214                 :     /* Only this hash method is supported currently */
                                215              43 :     Assert(hash_type == PG_SHA256);
                                216                 : 
   13 dgustafsson               217              43 :     Assert(iterations > 0);
                                218                 : 
                                219                 :     /* Calculate StoredKey and ServerKey */
  110 michael                   220              43 :     if (scram_SaltedPassword(password, hash_type, key_length,
                                221                 :                              salt, saltlen, iterations,
  451 michael                   222 GIC          43 :                              salted_password, errstr) < 0 ||
  110 michael                   223 GNC          43 :         scram_ClientKey(salted_password, hash_type, key_length,
                                224              43 :                         stored_key, errstr) < 0 ||
                                225              43 :         scram_H(stored_key, hash_type, key_length,
                                226              43 :                 stored_key, errstr) < 0 ||
                                227              43 :         scram_ServerKey(salted_password, hash_type, key_length,
                                228                 :                         server_key, errstr) < 0)
                                229                 :     {
                                230                 :         /* errstr is filled already here */
  858 michael                   231 ECB             : #ifdef FRONTEND
  858 michael                   232 UIC           0 :         return NULL;
  858 michael                   233 ECB             : #else
  451 michael                   234 LBC           0 :         elog(ERROR, "could not calculate stored key and server key: %s",
  451 michael                   235 ECB             :              *errstr);
  858                           236                 : #endif
                                237                 :     }
 2167 heikki.linnakangas        238                 : 
                                239                 :     /*----------
                                240                 :      * The format is:
                                241                 :      * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
                                242                 :      *----------
 2167 heikki.linnakangas        243 EUB             :      */
 1375 michael                   244 GIC          43 :     encoded_salt_len = pg_b64_enc_len(saltlen);
  110 michael                   245 GNC          43 :     encoded_stored_len = pg_b64_enc_len(key_length);
                                246              43 :     encoded_server_len = pg_b64_enc_len(key_length);
                                247                 : 
 2167 heikki.linnakangas        248 GIC          43 :     maxlen = strlen("SCRAM-SHA-256") + 1
                                249                 :         + 10 + 1                /* iteration count */
                                250                 :         + encoded_salt_len + 1  /* Base64-encoded salt */
 1375 michael                   251              43 :         + encoded_stored_len + 1    /* Base64-encoded StoredKey */
                                252              43 :         + encoded_server_len + 1;   /* Base64-encoded ServerKey */
                                253                 : 
                                254                 : #ifdef FRONTEND
 2167 heikki.linnakangas        255 CBC           1 :     result = malloc(maxlen);
                                256               1 :     if (!result)
  451 michael                   257 ECB             :     {
  451 michael                   258 UIC           0 :         *errstr = _("out of memory");
 2167 heikki.linnakangas        259 LBC           0 :         return NULL;
                                260                 :     }
                                261                 : #else
 2167 heikki.linnakangas        262 CBC          42 :     result = palloc(maxlen);
 2167 heikki.linnakangas        263 ECB             : #endif
                                264                 : 
 2167 heikki.linnakangas        265 GIC          43 :     p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
 2167 heikki.linnakangas        266 ECB             : 
 1375 michael                   267                 :     /* salt */
 1375 michael                   268 GIC          43 :     encoded_result = pg_b64_encode(salt, saltlen, p, encoded_salt_len);
 1375 michael                   269 GBC          43 :     if (encoded_result < 0)
 1375 michael                   270 EUB             :     {
  451 michael                   271 UIC           0 :         *errstr = _("could not encode salt");
                                272                 : #ifdef FRONTEND
 1375 michael                   273 LBC           0 :         free(result);
 1375 michael                   274 UIC           0 :         return NULL;
                                275                 : #else
  451 michael                   276 LBC           0 :         elog(ERROR, "%s", *errstr);
                                277                 : #endif
                                278                 :     }
 1375 michael                   279 CBC          43 :     p += encoded_result;
 2167 heikki.linnakangas        280              43 :     *(p++) = '$';
                                281                 : 
 1375 michael                   282 EUB             :     /* stored key */
  110 michael                   283 GNC          43 :     encoded_result = pg_b64_encode((char *) stored_key, key_length, p,
 1375 michael                   284 EUB             :                                    encoded_stored_len);
 1375 michael                   285 GBC          43 :     if (encoded_result < 0)
                                286                 :     {
  451 michael                   287 UBC           0 :         *errstr = _("could not encode stored key");
                                288                 : #ifdef FRONTEND
 1375 michael                   289 UIC           0 :         free(result);
 1375 michael                   290 LBC           0 :         return NULL;
 1375 michael                   291 ECB             : #else
  451 michael                   292 UIC           0 :         elog(ERROR, "%s", *errstr);
                                293                 : #endif
 1375 michael                   294 ECB             :     }
                                295                 : 
 1375 michael                   296 CBC          43 :     p += encoded_result;
 2167 heikki.linnakangas        297 GIC          43 :     *(p++) = ':';
 1375 michael                   298 EUB             : 
                                299                 :     /* server key */
  110 michael                   300 GNC          43 :     encoded_result = pg_b64_encode((char *) server_key, key_length, p,
 1375 michael                   301 EUB             :                                    encoded_server_len);
 1375 michael                   302 GIC          43 :     if (encoded_result < 0)
 1375 michael                   303 EUB             :     {
  451 michael                   304 UIC           0 :         *errstr = _("could not encode server key");
                                305                 : #ifdef FRONTEND
 1375                           306               0 :         free(result);
 1375 michael                   307 LBC           0 :         return NULL;
 1375 michael                   308 ECB             : #else
  451 michael                   309 UIC           0 :         elog(ERROR, "%s", *errstr);
                                310                 : #endif
 1375 michael                   311 ECB             :     }
                                312                 : 
 1375 michael                   313 CBC          43 :     p += encoded_result;
 2167 heikki.linnakangas        314 GIC          43 :     *(p++) = '\0';
 2167 heikki.linnakangas        315 EUB             : 
 2167 heikki.linnakangas        316 GIC          43 :     Assert(p - result <= maxlen);
 2167 heikki.linnakangas        317 EUB             : 
 2167 heikki.linnakangas        318 GBC          43 :     return result;
                                319                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a