YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/build/debugcov-clang-dynamic-arm64-ninja/postgres_build/src/interfaces/libpq/scram-common.c
Line
Count
Source (jump to first uncovered line)
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-2018, 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/scram-common.h"
24
#include "port/pg_bswap.h"
25
26
#define HMAC_IPAD 0x36
27
#define HMAC_OPAD 0x5C
28
29
/*
30
 * Calculate HMAC per RFC2104.
31
 *
32
 * The hash function used is SHA-256.
33
 */
34
void
35
scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
36
16.3k
{
37
16.3k
  uint8   k_ipad[SHA256_HMAC_B];
38
16.3k
  int     i;
39
16.3k
  uint8   keybuf[SCRAM_KEY_LEN];
40
41
  /*
42
   * If the key is longer than the block size (64 bytes for SHA-256), pass
43
   * it through SHA-256 once to shrink it down.
44
   */
45
16.3k
  if (keylen > SHA256_HMAC_B)
46
0
  {
47
0
    pg_sha256_ctx sha256_ctx;
48
49
0
    pg_sha256_init(&sha256_ctx);
50
0
    pg_sha256_update(&sha256_ctx, key, keylen);
51
0
    pg_sha256_final(&sha256_ctx, keybuf);
52
0
    key = keybuf;
53
0
    keylen = SCRAM_KEY_LEN;
54
0
  }
55
56
16.3k
  memset(k_ipad, HMAC_IPAD, SHA256_HMAC_B);
57
16.3k
  memset(ctx->k_opad, HMAC_OPAD, SHA256_HMAC_B);
58
59
65.7k
  for (i = 0; i < keylen; 
i++49.3k
)
60
49.3k
  {
61
49.3k
    k_ipad[i] ^= key[i];
62
49.3k
    ctx->k_opad[i] ^= key[i];
63
49.3k
  }
64
65
  /* tmp = H(K XOR ipad, text) */
66
16.3k
  pg_sha256_init(&ctx->sha256ctx);
67
16.3k
  pg_sha256_update(&ctx->sha256ctx, k_ipad, SHA256_HMAC_B);
68
16.3k
}
69
70
/*
71
 * Update HMAC calculation
72
 * The hash function used is SHA-256.
73
 */
74
void
75
scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
76
16.3k
{
77
16.3k
  pg_sha256_update(&ctx->sha256ctx, (const uint8 *) str, slen);
78
16.3k
}
79
80
/*
81
 * Finalize HMAC calculation.
82
 * The hash function used is SHA-256.
83
 */
84
void
85
scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
86
16.3k
{
87
16.3k
  uint8   h[SCRAM_KEY_LEN];
88
89
16.3k
  pg_sha256_final(&ctx->sha256ctx, h);
90
91
  /* H(K XOR opad, tmp) */
92
16.3k
  pg_sha256_init(&ctx->sha256ctx);
93
16.3k
  pg_sha256_update(&ctx->sha256ctx, ctx->k_opad, SHA256_HMAC_B);
94
16.3k
  pg_sha256_update(&ctx->sha256ctx, h, SCRAM_KEY_LEN);
95
16.3k
  pg_sha256_final(&ctx->sha256ctx, result);
96
16.3k
}
97
98
/*
99
 * Calculate SaltedPassword.
100
 *
101
 * The password should already be normalized by SASLprep.
102
 */
103
void
104
scram_SaltedPassword(const char *password,
105
           const char *salt, int saltlen, int iterations,
106
           uint8 *result)
107
4
{
108
4
  int     password_len = strlen(password);
109
4
  uint32    one = pg_hton32(1);
110
4
  int     i,
111
4
        j;
112
4
  uint8   Ui[SCRAM_KEY_LEN];
113
4
  uint8   Ui_prev[SCRAM_KEY_LEN];
114
4
  scram_HMAC_ctx hmac_ctx;
115
116
  /*
117
   * Iterate hash calculation of HMAC entry using given salt.  This is
118
   * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom
119
   * function.
120
   */
121
122
  /* First iteration */
123
4
  scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
124
4
  scram_HMAC_update(&hmac_ctx, salt, saltlen);
125
4
  scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32));
126
4
  scram_HMAC_final(Ui_prev, &hmac_ctx);
127
4
  memcpy(result, Ui_prev, SCRAM_KEY_LEN);
128
129
  /* Subsequent iterations */
130
16.3k
  for (i = 2; i <= iterations; 
i++16.3k
)
131
16.3k
  {
132
16.3k
    scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
133
16.3k
    scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN);
134
16.3k
    scram_HMAC_final(Ui, &hmac_ctx);
135
540k
    for (j = 0; j < SCRAM_KEY_LEN; 
j++524k
)
136
524k
      result[j] ^= Ui[j];
137
16.3k
    memcpy(Ui_prev, Ui, SCRAM_KEY_LEN);
138
16.3k
  }
139
4
}
140
141
142
/*
143
 * Calculate SHA-256 hash for a NULL-terminated string. (The NULL terminator is
144
 * not included in the hash).
145
 */
146
void
147
scram_H(const uint8 *input, int len, uint8 *result)
148
2
{
149
2
  pg_sha256_ctx ctx;
150
151
2
  pg_sha256_init(&ctx);
152
2
  pg_sha256_update(&ctx, input, len);
153
2
  pg_sha256_final(&ctx, result);
154
2
}
155
156
/*
157
 * Calculate ClientKey.
158
 */
159
void
160
scram_ClientKey(const uint8 *salted_password, uint8 *result)
161
2
{
162
2
  scram_HMAC_ctx ctx;
163
164
2
  scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
165
2
  scram_HMAC_update(&ctx, "Client Key", strlen("Client Key"));
166
2
  scram_HMAC_final(result, &ctx);
167
2
}
168
169
/*
170
 * Calculate ServerKey.
171
 */
172
void
173
scram_ServerKey(const uint8 *salted_password, uint8 *result)
174
4
{
175
4
  scram_HMAC_ctx ctx;
176
177
4
  scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
178
4
  scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
179
4
  scram_HMAC_final(result, &ctx);
180
4
}
181
182
183
/*
184
 * Construct a verifier string for SCRAM, stored in pg_authid.rolpassword.
185
 *
186
 * The password should already have been processed with SASLprep, if necessary!
187
 *
188
 * If iterations is 0, default number of iterations is used.  The result is
189
 * palloc'd or malloc'd, so caller is responsible for freeing it.
190
 */
191
char *
192
scram_build_verifier(const char *salt, int saltlen, int iterations,
193
           const char *password)
194
0
{
195
0
  uint8   salted_password[SCRAM_KEY_LEN];
196
0
  uint8   stored_key[SCRAM_KEY_LEN];
197
0
  uint8   server_key[SCRAM_KEY_LEN];
198
0
  char     *result;
199
0
  char     *p;
200
0
  int     maxlen;
201
202
0
  if (iterations <= 0)
203
0
    iterations = SCRAM_DEFAULT_ITERATIONS;
204
205
  /* Calculate StoredKey and ServerKey */
206
0
  scram_SaltedPassword(password, salt, saltlen, iterations,
207
0
             salted_password);
208
0
  scram_ClientKey(salted_password, stored_key);
209
0
  scram_H(stored_key, SCRAM_KEY_LEN, stored_key);
210
211
0
  scram_ServerKey(salted_password, server_key);
212
213
  /*----------
214
   * The format is:
215
   * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
216
   *----------
217
   */
218
0
  maxlen = strlen("SCRAM-SHA-256") + 1
219
0
    + 10 + 1        /* iteration count */
220
0
    + pg_b64_enc_len(saltlen) + 1 /* Base64-encoded salt */
221
0
    + pg_b64_enc_len(SCRAM_KEY_LEN) + 1 /* Base64-encoded StoredKey */
222
0
    + pg_b64_enc_len(SCRAM_KEY_LEN) + 1;  /* Base64-encoded ServerKey */
223
224
0
#ifdef FRONTEND
225
0
  result = malloc(maxlen);
226
0
  if (!result)
227
0
    return NULL;
228
#else
229
  result = palloc(maxlen);
230
#endif
231
232
0
  p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
233
234
0
  p += pg_b64_encode(salt, saltlen, p);
235
0
  *(p++) = '$';
236
0
  p += pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p);
237
0
  *(p++) = ':';
238
0
  p += pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p);
239
0
  *(p++) = '\0';
240
241
0
  Assert(p - result <= maxlen);
242
243
0
  return result;
244
0
}