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 
17 /* for htonl */
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <string.h>
21 #include "utils/elog.h"
22 #include "utils/palloc.h"
23 #include "utils/base64.h"
24 #include "auth/scram-common.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
scram_HMAC_init(scram_HMAC_ctx * ctx,const uint8 * key,int keylen)35 scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
36 {
37 	uint8		k_ipad[SHA256_HMAC_B];
38 	int			i;
39 	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 	if (keylen > SHA256_HMAC_B)
46 	{
47 		pg_sha256_ctx sha256_ctx;
48 
49 		pg_sha256_init(&sha256_ctx);
50 		pg_sha256_update(&sha256_ctx, key, keylen);
51 		pg_sha256_final(&sha256_ctx, keybuf);
52 		key = keybuf;
53 		keylen = SCRAM_KEY_LEN;
54 	}
55 
56 	memset(k_ipad, HMAC_IPAD, SHA256_HMAC_B);
57 	memset(ctx->k_opad, HMAC_OPAD, SHA256_HMAC_B);
58 
59 	for (i = 0; i < keylen; i++)
60 	{
61 		k_ipad[i] ^= key[i];
62 		ctx->k_opad[i] ^= key[i];
63 	}
64 
65 	/* tmp = H(K XOR ipad, text) */
66 	pg_sha256_init(&ctx->sha256ctx);
67 	pg_sha256_update(&ctx->sha256ctx, k_ipad, SHA256_HMAC_B);
68 }
69 
70 /*
71  * Update HMAC calculation
72  * The hash function used is SHA-256.
73  */
74 void
scram_HMAC_update(scram_HMAC_ctx * ctx,const char * str,int slen)75 scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
76 {
77 	pg_sha256_update(&ctx->sha256ctx, (const uint8 *) str, slen);
78 }
79 
80 /*
81  * Finalize HMAC calculation.
82  * The hash function used is SHA-256.
83  */
84 void
scram_HMAC_final(uint8 * result,scram_HMAC_ctx * ctx)85 scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
86 {
87 	uint8		h[SCRAM_KEY_LEN];
88 
89 	pg_sha256_final(&ctx->sha256ctx, h);
90 
91 	/* H(K XOR opad, tmp) */
92 	pg_sha256_init(&ctx->sha256ctx);
93 	pg_sha256_update(&ctx->sha256ctx, ctx->k_opad, SHA256_HMAC_B);
94 	pg_sha256_update(&ctx->sha256ctx, h, SCRAM_KEY_LEN);
95 	pg_sha256_final(&ctx->sha256ctx, result);
96 }
97 
98 /*
99  * Calculate SaltedPassword.
100  *
101  * The password should already be normalized by SASLprep.
102  */
103 void
scram_SaltedPassword(const char * password,const char * salt,int saltlen,int iterations,uint8 * result)104 scram_SaltedPassword(const char *password,
105 					 const char *salt, int saltlen, int iterations,
106 					 uint8 *result)
107 {
108 	int			password_len = strlen(password);
109 	uint32		one = htonl(1);
110 	int			i,
111 				j;
112 	uint8		Ui[SCRAM_KEY_LEN];
113 	uint8		Ui_prev[SCRAM_KEY_LEN];
114 	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 	scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
124 	scram_HMAC_update(&hmac_ctx, salt, saltlen);
125 	scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32));
126 	scram_HMAC_final(Ui_prev, &hmac_ctx);
127 	memcpy(result, Ui_prev, SCRAM_KEY_LEN);
128 
129 	/* Subsequent iterations */
130 	for (i = 2; i <= iterations; i++)
131 	{
132 		scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
133 		scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN);
134 		scram_HMAC_final(Ui, &hmac_ctx);
135 		for (j = 0; j < SCRAM_KEY_LEN; j++)
136 			result[j] ^= Ui[j];
137 		memcpy(Ui_prev, Ui, SCRAM_KEY_LEN);
138 	}
139 }
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
scram_H(const uint8 * input,int len,uint8 * result)147 scram_H(const uint8 *input, int len, uint8 *result)
148 {
149 	pg_sha256_ctx ctx;
150 
151 	pg_sha256_init(&ctx);
152 	pg_sha256_update(&ctx, input, len);
153 	pg_sha256_final(&ctx, result);
154 }
155 
156 /*
157  * Calculate ClientKey.
158  */
159 void
scram_ClientKey(const uint8 * salted_password,uint8 * result)160 scram_ClientKey(const uint8 *salted_password, uint8 *result)
161 {
162 	scram_HMAC_ctx ctx;
163 
164 	scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
165 	scram_HMAC_update(&ctx, "Client Key", strlen("Client Key"));
166 	scram_HMAC_final(result, &ctx);
167 }
168 
169 /*
170  * Calculate ServerKey.
171  */
172 void
scram_ServerKey(const uint8 * salted_password,uint8 * result)173 scram_ServerKey(const uint8 *salted_password, uint8 *result)
174 {
175 	scram_HMAC_ctx ctx;
176 
177 	scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
178 	scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
179 	scram_HMAC_final(result, &ctx);
180 }
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 *
scram_build_verifier(const char * salt,int saltlen,int iterations,const char * password)192 scram_build_verifier(const char *salt, int saltlen, int iterations,
193 					 const char *password)
194 {
195 	uint8		salted_password[SCRAM_KEY_LEN];
196 	uint8		stored_key[SCRAM_KEY_LEN];
197 	uint8		server_key[SCRAM_KEY_LEN];
198 	char	   *result;
199 	char	   *p;
200 	int			maxlen;
201 
202 	if (iterations <= 0)
203 		iterations = SCRAM_DEFAULT_ITERATIONS;
204 
205 	/* Calculate StoredKey and ServerKey */
206 	scram_SaltedPassword(password, salt, saltlen, iterations,
207 						 salted_password);
208 	scram_ClientKey(salted_password, stored_key);
209 	scram_H(stored_key, SCRAM_KEY_LEN, stored_key);
210 
211 	scram_ServerKey(salted_password, server_key);
212 
213 	/*----------
214 	 * The format is:
215 	 * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
216 	 *----------
217 	 */
218 	maxlen = strlen("SCRAM-SHA-256") + 1
219 		+ 10 + 1				/* iteration count */
220 		+ pg_b64_enc_len(saltlen) + 1	/* Base64-encoded salt */
221 		+ pg_b64_enc_len(SCRAM_KEY_LEN) + 1 /* Base64-encoded StoredKey */
222 		+ pg_b64_enc_len(SCRAM_KEY_LEN) + 1;	/* Base64-encoded ServerKey */
223 
224 	result = palloc(maxlen);
225 
226 	p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
227 
228 	p += pg_b64_encode(salt, saltlen, p);
229 	*(p++) = '$';
230 	p += pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p);
231 	*(p++) = ':';
232 	p += pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p);
233 	*(p++) = '\0';
234 
235 	Assert(p - result <= maxlen);
236 
237 	return result;
238 }
239