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
scram_HMAC_init(scram_HMAC_ctx * ctx,const uint8 * key,int keylen)38 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 	if (keylen > SHA256_HMAC_B)
49 	{
50 		pg_sha256_ctx sha256_ctx;
51 
52 		pg_sha256_init(&sha256_ctx);
53 		pg_sha256_update(&sha256_ctx, key, keylen);
54 		pg_sha256_final(&sha256_ctx, keybuf);
55 		key = keybuf;
56 		keylen = SCRAM_KEY_LEN;
57 	}
58 
59 	memset(k_ipad, HMAC_IPAD, SHA256_HMAC_B);
60 	memset(ctx->k_opad, HMAC_OPAD, SHA256_HMAC_B);
61 
62 	for (i = 0; i < keylen; i++)
63 	{
64 		k_ipad[i] ^= key[i];
65 		ctx->k_opad[i] ^= key[i];
66 	}
67 
68 	/* tmp = H(K XOR ipad, text) */
69 	pg_sha256_init(&ctx->sha256ctx);
70 	pg_sha256_update(&ctx->sha256ctx, k_ipad, SHA256_HMAC_B);
71 }
72 
73 /*
74  * Update HMAC calculation
75  * The hash function used is SHA-256.
76  */
77 void
scram_HMAC_update(scram_HMAC_ctx * ctx,const char * str,int slen)78 scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
79 {
80 	pg_sha256_update(&ctx->sha256ctx, (const uint8 *) str, slen);
81 }
82 
83 /*
84  * Finalize HMAC calculation.
85  * The hash function used is SHA-256.
86  */
87 void
scram_HMAC_final(uint8 * result,scram_HMAC_ctx * ctx)88 scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
89 {
90 	uint8		h[SCRAM_KEY_LEN];
91 
92 	pg_sha256_final(&ctx->sha256ctx, h);
93 
94 	/* H(K XOR opad, tmp) */
95 	pg_sha256_init(&ctx->sha256ctx);
96 	pg_sha256_update(&ctx->sha256ctx, ctx->k_opad, SHA256_HMAC_B);
97 	pg_sha256_update(&ctx->sha256ctx, h, SCRAM_KEY_LEN);
98 	pg_sha256_final(&ctx->sha256ctx, result);
99 }
100 
101 /*
102  * Calculate SaltedPassword.
103  *
104  * The password should already be normalized by SASLprep.
105  */
106 void
scram_SaltedPassword(const char * password,const char * salt,int saltlen,int iterations,uint8 * result)107 scram_SaltedPassword(const char *password,
108 					 const char *salt, int saltlen, int iterations,
109 					 uint8 *result)
110 {
111 	int			password_len = strlen(password);
112 	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 	scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
127 	scram_HMAC_update(&hmac_ctx, salt, saltlen);
128 	scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32));
129 	scram_HMAC_final(Ui_prev, &hmac_ctx);
130 	memcpy(result, Ui_prev, SCRAM_KEY_LEN);
131 
132 	/* Subsequent iterations */
133 	for (i = 2; i <= iterations; i++)
134 	{
135 		scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
136 		scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN);
137 		scram_HMAC_final(Ui, &hmac_ctx);
138 		for (j = 0; j < SCRAM_KEY_LEN; j++)
139 			result[j] ^= Ui[j];
140 		memcpy(Ui_prev, Ui, SCRAM_KEY_LEN);
141 	}
142 }
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
scram_H(const uint8 * input,int len,uint8 * result)150 scram_H(const uint8 *input, int len, uint8 *result)
151 {
152 	pg_sha256_ctx ctx;
153 
154 	pg_sha256_init(&ctx);
155 	pg_sha256_update(&ctx, input, len);
156 	pg_sha256_final(&ctx, result);
157 }
158 
159 /*
160  * Calculate ClientKey.
161  */
162 void
scram_ClientKey(const uint8 * salted_password,uint8 * result)163 scram_ClientKey(const uint8 *salted_password, uint8 *result)
164 {
165 	scram_HMAC_ctx ctx;
166 
167 	scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
168 	scram_HMAC_update(&ctx, "Client Key", strlen("Client Key"));
169 	scram_HMAC_final(result, &ctx);
170 }
171 
172 /*
173  * Calculate ServerKey.
174  */
175 void
scram_ServerKey(const uint8 * salted_password,uint8 * result)176 scram_ServerKey(const uint8 *salted_password, uint8 *result)
177 {
178 	scram_HMAC_ctx ctx;
179 
180 	scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
181 	scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
182 	scram_HMAC_final(result, &ctx);
183 }
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 *
scram_build_verifier(const char * salt,int saltlen,int iterations,const char * password)195 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 	if (iterations <= 0)
206 		iterations = SCRAM_DEFAULT_ITERATIONS;
207 
208 	/* Calculate StoredKey and ServerKey */
209 	scram_SaltedPassword(password, salt, saltlen, iterations,
210 						 salted_password);
211 	scram_ClientKey(salted_password, stored_key);
212 	scram_H(stored_key, SCRAM_KEY_LEN, stored_key);
213 
214 	scram_ServerKey(salted_password, server_key);
215 
216 	/*----------
217 	 * The format is:
218 	 * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
219 	 *----------
220 	 */
221 	maxlen = strlen("SCRAM-SHA-256") + 1
222 		+ 10 + 1				/* iteration count */
223 		+ pg_b64_enc_len(saltlen) + 1	/* Base64-encoded salt */
224 		+ pg_b64_enc_len(SCRAM_KEY_LEN) + 1 /* Base64-encoded StoredKey */
225 		+ 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 	result = palloc(maxlen);
233 #endif
234 
235 	p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
236 
237 	p += pg_b64_encode(salt, saltlen, p);
238 	*(p++) = '$';
239 	p += pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p);
240 	*(p++) = ':';
241 	p += pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p);
242 	*(p++) = '\0';
243 
244 	Assert(p - result <= maxlen);
245 
246 	return result;
247 }
248