1 /* scram-simple.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 that
22 SALT/ITER/SALTED_PASSWORD/SERVERKEY/STOREDKEY properties are set
23 after completing authentication without setting the properties, and
24 also that the SCRAM mechanism works without a callback if the
25 required properties are available. */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdbool.h>
36
37 #include "utils.h"
38
39 #define USERNAME "user"
40 #define PASSWORD "pencil"
41
42 void
doit(void)43 doit (void)
44 {
45 Gsasl *ctx = NULL;
46 Gsasl_session *server = NULL, *client = NULL;
47 char *s1, *s2;
48 size_t s1len, s2len;
49 int res;
50
51 res = gsasl_init (&ctx);
52 if (res != GSASL_OK)
53 {
54 fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res));
55 return;
56 }
57
58 if (!gsasl_client_support_p (ctx, "SCRAM-SHA-256")
59 || !gsasl_server_support_p (ctx, "SCRAM-SHA-256"))
60 {
61 gsasl_done (ctx);
62 fail ("No support for SCRAM-SHA-256.\n");
63 exit (77);
64 }
65
66 res = gsasl_server_start (ctx, "SCRAM-SHA-256", &server);
67 if (res != GSASL_OK)
68 {
69 fail ("gsasl_server_start() failed (%d):\n%s\n",
70 res, gsasl_strerror (res));
71 return;
72 }
73 res = gsasl_client_start (ctx, "SCRAM-SHA-256", &client);
74 if (res != GSASL_OK)
75 {
76 fail ("gsasl_client_start() failed (%d):\n%s\n",
77 res, gsasl_strerror (res));
78 return;
79 }
80
81 gsasl_property_set (client, GSASL_PASSWORD, PASSWORD);
82 gsasl_property_set (server, GSASL_PASSWORD, PASSWORD);
83 gsasl_property_set (client, GSASL_AUTHID, USERNAME);
84 gsasl_property_set (server, GSASL_AUTHID, USERNAME);
85
86 s1 = NULL;
87 s1len = 0;
88
89 /* Client first... */
90
91 res = gsasl_step (client, s1, s1len, &s1, &s1len);
92 if (res != GSASL_NEEDS_MORE)
93 {
94 fail ("gsasl_step(1) failed (%d):\n%s\n", res, gsasl_strerror (res));
95 return;
96 }
97
98 if (debug)
99 printf ("C: %.*s [%c]\n", (int) s1len, s1, res == GSASL_OK ? 'O' : 'N');
100
101 /* Server first... */
102
103 res = gsasl_step (server, s1, s1len, &s2, &s2len);
104 gsasl_free (s1);
105 if (res != GSASL_NEEDS_MORE)
106 {
107 fail ("gsasl_step(2) failed (%d):\n%s\n", res, gsasl_strerror (res));
108 return;
109 }
110
111 if (debug)
112 printf ("S: %.*s [%c]\n", (int) s2len, s2, res == GSASL_OK ? 'O' : 'N');
113
114 /* Client final... */
115
116 res = gsasl_step (client, s2, s2len, &s1, &s1len);
117 gsasl_free (s2);
118 if (res != GSASL_NEEDS_MORE)
119 {
120 fail ("gsasl_step(3) failed (%d):\n%s\n", res, gsasl_strerror (res));
121 return;
122 }
123
124 if (debug)
125 printf ("C: %.*s [%c]\n", (int) s1len, s1, res == GSASL_OK ? 'O' : 'N');
126
127 /* Server final... */
128
129 res = gsasl_step (server, s1, s1len, &s2, &s2len);
130 gsasl_free (s1);
131 if (res != GSASL_OK)
132 {
133 fail ("gsasl_step(4) failed (%d):\n%s\n", res, gsasl_strerror (res));
134 return;
135 }
136
137 if (debug)
138 printf ("S: %.*s [%c]\n\n", (int) s2len, s2, res == GSASL_OK ? 'O' : 'N');
139
140 /* Let client parse server final... */
141
142 res = gsasl_step (client, s2, s2len, &s1, &s1len);
143 gsasl_free (s2);
144 if (res != GSASL_OK)
145 {
146 fail ("gsasl_step(5) failed (%d):\n%s\n", res, gsasl_strerror (res));
147 return;
148 }
149
150 if (s1len != 0)
151 fail ("dummy final client step produced output?!\n");
152
153 {
154 const char *p = gsasl_property_fast (server, GSASL_AUTHID);
155 if (p && strcmp (p, USERNAME) != 0)
156 fail ("Bad authid? %s != %s\n", p, USERNAME);
157 if (debug)
158 printf ("GSASL_AUTHID: %s\n", p);
159 }
160
161 {
162 const char *ci = gsasl_property_fast (client, GSASL_SCRAM_ITER);
163 const char *si = gsasl_property_fast (server, GSASL_SCRAM_ITER);
164 if (debug)
165 {
166 printf ("GSASL_SCRAM_ITER (client): %s\n", ci);
167 printf ("GSASL_SCRAM_ITER (server): %s\n", si);
168 }
169 if (!ci || !si || strcmp (ci, si) != 0)
170 fail ("scram iter mismatch\n");
171 }
172
173 {
174 const char *cs = gsasl_property_fast (client, GSASL_SCRAM_SALT);
175 const char *ss = gsasl_property_fast (server, GSASL_SCRAM_SALT);
176 if (debug)
177 {
178 printf ("GSASL_SCRAM_SALT (client): %s\n", cs);
179 printf ("GSASL_SCRAM_SALT (server): %s\n", ss);
180 }
181 if (!cs || !ss || strcmp (cs, ss) != 0)
182 fail ("scram salt mismatch\n");
183 }
184
185 {
186 const char *csp =
187 gsasl_property_fast (client, GSASL_SCRAM_SALTED_PASSWORD);
188 const char *ssp =
189 gsasl_property_fast (server, GSASL_SCRAM_SALTED_PASSWORD);
190
191 if (debug)
192 {
193 printf ("GSASL_SCRAM_SALTED_PASSWORD (client): %s\n", csp);
194 printf ("GSASL_SCRAM_SALTED_PASSWORD (server): %s\n", ssp);
195 }
196 if (!csp || !ssp || strcmp (csp, ssp) != 0)
197 fail ("scram salted password mismatch\n");
198 }
199
200 {
201 const char *sek = gsasl_property_fast (server, GSASL_SCRAM_SERVERKEY);
202 const char *stk = gsasl_property_fast (server, GSASL_SCRAM_STOREDKEY);
203
204 if (debug)
205 {
206 printf ("GSASL_SCRAM_SERVERKEY: %s\n", sek);
207 printf ("GSASL_SCRAM_STOREDKEY: %s\n", stk);
208 }
209
210 if (!sek)
211 fail ("missing ServerKey\n");
212 if (!stk)
213 fail ("missing StoredKey\n");
214 }
215
216 if (debug)
217 printf ("\n");
218
219 gsasl_finish (client);
220 gsasl_finish (server);
221
222 gsasl_done (ctx);
223 }
224