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