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