1 /* scram-nopasswd.c --- Test the SCRAM-SHA256 mechanism.
2 * Copyright (C) 2009-2021 Simon Josefsson
3 *
4 * This file is part of GNU SASL.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 /* This self-test is about making sure SCRAM works without a supplied
22 password both in client and server mode. */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdbool.h>
33
34 #include "utils.h"
35
36 /*
37 $ src/gsasl --mkpasswd --password pencil --mechanism SCRAM-SHA-256 --iteration-count 4096 --salt 8tkvpwuPHUIvxZdV
38 SCRAM-SHA-256:4096:8tkvpwuPHUIvxZdV:kx5HW/tXBntkDU9vYAphILpp9GkCBpYXdb7G6n5B/y4=:CwOgbBjlXTbH2gXK5XKich7UnzHrMh5vre1ipvSW0jE=:9e1uUmKhrFexDKE2zfHs3aCuRANzfnf5EQG6MFXvmKM=
39 $
40 */
41
42 #define USERNAME "user"
43 #define ITER "4096"
44 #define SALT "8tkvpwuPHUIvxZdV"
45 #define SALTED_PASSWORD "931e475bfb57067b640d4f6f600a6120" \
46 "ba69f4690206961775bec6ea7e41ff2e"
47 #define SERVERKEY "CwOgbBjlXTbH2gXK5XKich7UnzHrMh5vre1ipvSW0jE="
48 #define STOREDKEY "9e1uUmKhrFexDKE2zfHs3aCuRANzfnf5EQG6MFXvmKM="
49
50 static int
callback(Gsasl * ctx,Gsasl_session * sctx,Gsasl_property prop)51 callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
52 {
53 int rc = GSASL_NO_CALLBACK;
54
55 /* Get user info from user. */
56
57 switch (prop)
58 {
59 case GSASL_SCRAM_SALTED_PASSWORD:
60 gsasl_property_set (sctx, prop, SALTED_PASSWORD);
61 rc = GSASL_OK;
62 break;
63
64 case GSASL_SCRAM_SERVERKEY:
65 gsasl_property_set (sctx, prop, SERVERKEY);
66 rc = GSASL_OK;
67 break;
68
69 case GSASL_SCRAM_STOREDKEY:
70 gsasl_property_set (sctx, prop, STOREDKEY);
71 rc = GSASL_OK;
72 break;
73
74 case GSASL_SCRAM_ITER:
75 gsasl_property_set (sctx, prop, ITER);
76 rc = GSASL_OK;
77 break;
78
79 case GSASL_SCRAM_SALT:
80 gsasl_property_set (sctx, prop, SALT);
81 rc = GSASL_OK;
82 break;
83
84 case GSASL_AUTHID:
85 gsasl_property_set (sctx, prop, USERNAME);
86 rc = GSASL_OK;
87 break;
88
89 case GSASL_PASSWORD:
90 case GSASL_CB_TLS_UNIQUE:
91 case GSASL_AUTHZID:
92 break;
93
94 default:
95 fail ("Unknown callback property %u\n", prop);
96 break;
97 }
98
99 return rc;
100 }
101
102 void
doit(void)103 doit (void)
104 {
105 Gsasl *ctx = NULL;
106 Gsasl_session *server = NULL, *client = NULL;
107 char *s1, *s2;
108 size_t s1len, s2len;
109 int res;
110
111 res = gsasl_init (&ctx);
112 if (res != GSASL_OK)
113 {
114 fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res));
115 return;
116 }
117
118 if (!gsasl_client_support_p (ctx, "SCRAM-SHA-256")
119 || !gsasl_server_support_p (ctx, "SCRAM-SHA-256"))
120 {
121 gsasl_done (ctx);
122 fail ("No support for SCRAM-SHA-256.\n");
123 exit (77);
124 }
125
126 gsasl_callback_set (ctx, callback);
127
128 res = gsasl_server_start (ctx, "SCRAM-SHA-256", &server);
129 if (res != GSASL_OK)
130 {
131 fail ("gsasl_server_start() failed (%d):\n%s\n",
132 res, gsasl_strerror (res));
133 return;
134 }
135 res = gsasl_client_start (ctx, "SCRAM-SHA-256", &client);
136 if (res != GSASL_OK)
137 {
138 fail ("gsasl_client_start() failed (%d):\n%s\n",
139 res, gsasl_strerror (res));
140 return;
141 }
142
143 s1 = NULL;
144 s1len = 0;
145
146 /* Client first... */
147
148 res = gsasl_step (client, s1, s1len, &s1, &s1len);
149 if (res != GSASL_NEEDS_MORE)
150 {
151 fail ("gsasl_step(1) failed (%d):\n%s\n", res, gsasl_strerror (res));
152 return;
153 }
154
155 if (debug)
156 printf ("C: %.*s [%c]\n", (int) s1len, s1, res == GSASL_OK ? 'O' : 'N');
157
158 /* Server first... */
159
160 res = gsasl_step (server, s1, s1len, &s2, &s2len);
161 gsasl_free (s1);
162 if (res != GSASL_NEEDS_MORE)
163 {
164 fail ("gsasl_step(2) failed (%d):\n%s\n", res, gsasl_strerror (res));
165 return;
166 }
167
168 if (debug)
169 printf ("S: %.*s [%c]\n", (int) s2len, s2, res == GSASL_OK ? 'O' : 'N');
170
171 /* Client final... */
172
173 res = gsasl_step (client, s2, s2len, &s1, &s1len);
174 gsasl_free (s2);
175 if (res != GSASL_NEEDS_MORE)
176 {
177 fail ("gsasl_step(3) failed (%d):\n%s\n", res, gsasl_strerror (res));
178 return;
179 }
180
181 if (debug)
182 printf ("C: %.*s [%c]\n", (int) s1len, s1, res == GSASL_OK ? 'O' : 'N');
183
184 /* Server final... */
185
186 res = gsasl_step (server, s1, s1len, &s2, &s2len);
187 gsasl_free (s1);
188 if (res != GSASL_OK)
189 {
190 fail ("gsasl_step(4) failed (%d):\n%s\n", res, gsasl_strerror (res));
191 return;
192 }
193
194 if (debug)
195 printf ("S: %.*s [%c]\n", (int) s2len, s2, res == GSASL_OK ? 'O' : 'N');
196
197 /* Let client parse server final... */
198
199 res = gsasl_step (client, s2, s2len, &s1, &s1len);
200 gsasl_free (s2);
201 if (res != GSASL_OK)
202 {
203 fail ("gsasl_step(5) failed (%d):\n%s\n", res, gsasl_strerror (res));
204 return;
205 }
206
207 if (s1len != 0)
208 fail ("dummy final client step produced output?!\n");
209
210 {
211 const char *p = gsasl_property_fast (server, GSASL_AUTHID);
212 if (p && strcmp (p, USERNAME) != 0)
213 fail ("Bad authid? %s != %s\n", p, USERNAME);
214 if (debug)
215 printf ("GSASL_AUTHID: %s\n", p);
216 }
217
218 {
219 const char *ci = gsasl_property_fast (client, GSASL_SCRAM_ITER);
220 const char *si = gsasl_property_fast (server, GSASL_SCRAM_ITER);
221 if (debug)
222 {
223 printf ("GSASL_SCRAM_ITER (client): %s\n", ci);
224 printf ("GSASL_SCRAM_ITER (server): %s\n", si);
225 }
226 if (!ci || !si || strcmp (ci, si) != 0)
227 fail ("scram iter mismatch\n");
228 }
229
230 {
231 const char *cs = gsasl_property_fast (client, GSASL_SCRAM_SALT);
232 const char *ss = gsasl_property_fast (server, GSASL_SCRAM_SALT);
233 if (debug)
234 {
235 printf ("GSASL_SCRAM_ITER (client): %s\n", cs);
236 printf ("GSASL_SCRAM_ITER (server): %s\n", ss);
237 }
238 if (!cs || !ss || strcmp (cs, ss) != 0)
239 fail ("scram salt mismatch\n");
240 }
241
242 {
243 const char *csp =
244 gsasl_property_fast (client, GSASL_SCRAM_SALTED_PASSWORD);
245 const char *ssp =
246 gsasl_property_fast (server, GSASL_SCRAM_SALTED_PASSWORD);
247
248 if (debug)
249 {
250 printf ("GSASL_SCRAM_SALTED_PASSWORD (client): %s\n", csp);
251 printf ("GSASL_SCRAM_SALTED_PASSWORD (server): %s\n", ssp);
252 }
253 if (!csp || strcmp (csp, SALTED_PASSWORD) != 0)
254 fail ("client scram salted password mismatch\n");
255 if (ssp)
256 fail ("server salted password set?\n");
257 }
258
259 {
260 const char *sek = gsasl_property_fast (server, GSASL_SCRAM_SERVERKEY);
261 const char *stk = gsasl_property_fast (server, GSASL_SCRAM_STOREDKEY);
262
263 if (debug)
264 {
265 printf ("GSASL_SCRAM_SERVERKEY: %s\n", sek);
266 printf ("GSASL_SCRAM_STOREDKEY: %s\n", stk);
267 }
268
269 if (!sek)
270 fail ("missing ServerKey\n");
271 if (!stk)
272 fail ("missing StoredKey\n");
273 if (strcmp (sek, SERVERKEY) != 0)
274 fail ("invalid ServerKey\n");
275 if (strcmp (stk, STOREDKEY) != 0)
276 fail ("invalid StoredKey\n");
277 }
278
279 if (debug)
280 printf ("\n");
281
282 gsasl_finish (client);
283 gsasl_finish (server);
284
285 gsasl_done (ctx);
286 }
287