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