gsasl  2.2.1
scram/parser.c
Go to the documentation of this file.
1 /* parser.c --- SCRAM parser.
2  * Copyright (C) 2009-2024 Simon Josefsson
3  *
4  * This file is part of GNU SASL Library.
5  *
6  * GNU SASL Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GNU SASL Library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GNU SASL Library; if not, write to the Free
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include <config.h>
24 
25 /* Get prototypes. */
26 #include "parser.h"
27 
28 /* Get malloc, free. */
29 #include <stdlib.h>
30 
31 /* Get memcpy, strlen. */
32 #include <string.h>
33 
34 /* Get validator. */
35 #include "validate.h"
36 
37 /* Get c_isalpha. */
38 #include "c-ctype.h"
39 
40 static char *
41 unescape (const char *str, size_t len)
42 {
43  char *out = malloc (len + 1);
44  char *p = out;
45 
46  if (!out)
47  return NULL;
48 
49  while (len > 0 && *str)
50  {
51  if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
52  {
53  *p++ = ',';
54  str += 3;
55  len -= 3;
56  }
57  else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
58  {
59  *p++ = '=';
60  str += 3;
61  len -= 3;
62  }
63  else
64  {
65  *p++ = *str;
66  str++;
67  len--;
68  }
69  }
70  *p = '\0';
71 
72  return out;
73 }
74 
75 int
76 scram_parse_client_first (const char *str, size_t len,
77  struct scram_client_first *cf)
78 {
80 
81  /* Minimum client first string is 'n,,n=a,r=b'. */
82  if (strnlen (str, len) < 10)
83  return -1;
84 
85  if (len == 0 || (*str != 'n' && *str != 'y' && *str != 'p'))
86  return -1;
87  cf->cbflag = *str;
88  str++, len--;
89 
90  if (cf->cbflag == 'p')
91  {
92  const char *p;
93 
94  if (len == 0 || *str != '=')
95  return -1;
96  str++, len--;
97 
98  p = memchr (str, ',', len);
99  if (!p)
100  return -1;
101  cf->cbname = malloc (p - str + 1);
102  if (!cf->cbname)
103  return -1;
104  memcpy (cf->cbname, str, p - str);
105  cf->cbname[p - str] = '\0';
106  len -= (p - str);
107  str += (p - str);
108  }
109 
110  if (len == 0 || *str != ',')
111  return -1;
112  str++, len--;
113 
114  if (len == 0)
115  return -1;
116  if (*str == 'a')
117  {
118  const char *p;
119  size_t l;
120 
121  str++, len--;
122  if (len == 0 || *str != '=')
123  return -1;
124  str++, len--;
125 
126  p = memchr (str, ',', len);
127  if (!p)
128  return -1;
129 
130  l = p - str;
131  if (len < l)
132  return -1;
133 
134  cf->authzid = unescape (str, l);
135  if (!cf->authzid)
136  return -1;
137 
138  str = p;
139  len -= l;
140  }
141 
142  if (len == 0 || *str != ',')
143  return -1;
144  str++, len--;
145 
146  if (len == 0 || *str != 'n')
147  return -1;
148  str++, len--;
149 
150  if (len == 0 || *str != '=')
151  return -1;
152  str++, len--;
153 
154  {
155  const char *p;
156  size_t l;
157 
158  p = memchr (str, ',', len);
159  if (!p)
160  return -1;
161 
162  l = p - str;
163  if (len < l)
164  return -1;
165 
166  cf->username = unescape (str, l);
167  if (!cf->username)
168  return -1;
169 
170  str = p;
171  len -= l;
172  }
173 
174  if (len == 0 || *str != ',')
175  return -1;
176  str++, len--;
177 
178  if (len == 0 || *str != 'r')
179  return -1;
180  str++, len--;
181 
182  if (len == 0 || *str != '=')
183  return -1;
184  str++, len--;
185 
186  {
187  const char *p;
188  size_t l;
189 
190  p = memchr (str, ',', len);
191  if (!p)
192  p = str + len;
193 
194  l = p - str;
195  if (len < l)
196  return -1;
197 
198  cf->client_nonce = malloc (l + 1);
199  if (!cf->client_nonce)
200  return -1;
201 
202  memcpy (cf->client_nonce, str, l);
203  cf->client_nonce[l] = '\0';
204 
205  str = p;
206  len -= l;
207  }
208 
209  /* FIXME check that any extension fields follow valid syntax. */
210 
211  if (!scram_valid_client_first (cf))
212  return -1;
213 
214  return 0;
215 }
216 
217 int
218 scram_parse_server_first (const char *str, size_t len,
219  struct scram_server_first *sf)
220 {
222 
223  /* Minimum server first string is 'r=ab,s=biws,i=1'. */
224  if (strnlen (str, len) < 15)
225  return -1;
226 
227  if (len == 0 || *str != 'r')
228  return -1;
229  str++, len--;
230 
231  if (len == 0 || *str != '=')
232  return -1;
233  str++, len--;
234 
235  {
236  const char *p;
237  size_t l;
238 
239  p = memchr (str, ',', len);
240  if (!p)
241  return -1;
242 
243  l = p - str;
244  if (len < l)
245  return -1;
246 
247  sf->nonce = malloc (l + 1);
248  if (!sf->nonce)
249  return -1;
250 
251  memcpy (sf->nonce, str, l);
252  sf->nonce[l] = '\0';
253 
254  str = p;
255  len -= l;
256  }
257 
258  if (len == 0 || *str != ',')
259  return -1;
260  str++, len--;
261 
262  if (len == 0 || *str != 's')
263  return -1;
264  str++, len--;
265 
266  if (len == 0 || *str != '=')
267  return -1;
268  str++, len--;
269 
270  {
271  const char *p;
272  size_t l;
273 
274  p = memchr (str, ',', len);
275  if (!p)
276  return -1;
277 
278  l = p - str;
279  if (len < l)
280  return -1;
281 
282  sf->salt = malloc (l + 1);
283  if (!sf->salt)
284  return -1;
285 
286  memcpy (sf->salt, str, l);
287  sf->salt[l] = '\0';
288 
289  str = p;
290  len -= l;
291  }
292 
293  if (len == 0 || *str != ',')
294  return -1;
295  str++, len--;
296 
297  if (len == 0 || *str != 'i')
298  return -1;
299  str++, len--;
300 
301  if (len == 0 || *str != '=')
302  return -1;
303  str++, len--;
304 
305  sf->iter = 0;
306  for (; len > 0 && *str >= '0' && *str <= '9'; str++, len--)
307  {
308  size_t last_iter = sf->iter;
309 
310  sf->iter = sf->iter * 10 + (*str - '0');
311 
312  /* Protect against wrap arounds. */
313  if (sf->iter < last_iter)
314  return -1;
315  }
316 
317  if (len > 0 && *str != ',')
318  return -1;
319 
320  /* FIXME check that any extension fields follow valid syntax. */
321 
322  if (!scram_valid_server_first (sf))
323  return -1;
324 
325  return 0;
326 }
327 
328 int
329 scram_parse_client_final (const char *str, size_t len,
330  struct scram_client_final *cl)
331 {
333 
334  /* Minimum client final string is 'c=biws,r=ab,p=ab=='. */
335  if (strnlen (str, len) < 18)
336  return -1;
337 
338  if (len == 0 || *str != 'c')
339  return -1;
340  str++, len--;
341 
342  if (len == 0 || *str != '=')
343  return -1;
344  str++, len--;
345 
346  {
347  const char *p;
348  size_t l;
349 
350  p = memchr (str, ',', len);
351  if (!p)
352  return -1;
353 
354  l = p - str;
355  if (len < l)
356  return -1;
357 
358  cl->cbind = malloc (l + 1);
359  if (!cl->cbind)
360  return -1;
361 
362  memcpy (cl->cbind, str, l);
363  cl->cbind[l] = '\0';
364 
365  str = p;
366  len -= l;
367  }
368 
369  if (len == 0 || *str != ',')
370  return -1;
371  str++, len--;
372 
373  if (len == 0 || *str != 'r')
374  return -1;
375  str++, len--;
376 
377  if (len == 0 || *str != '=')
378  return -1;
379  str++, len--;
380 
381  {
382  const char *p;
383  size_t l;
384 
385  p = memchr (str, ',', len);
386  if (!p)
387  return -1;
388 
389  l = p - str;
390  if (len < l)
391  return -1;
392 
393  cl->nonce = malloc (l + 1);
394  if (!cl->nonce)
395  return -1;
396 
397  memcpy (cl->nonce, str, l);
398  cl->nonce[l] = '\0';
399 
400  str = p;
401  len -= l;
402  }
403 
404  if (len == 0 || *str != ',')
405  return -1;
406  str++, len--;
407 
408  /* Ignore extensions. */
409  while (len > 0 && c_isalpha (*str) && *str != 'p')
410  {
411  const char *p;
412  size_t l;
413 
414  str++, len--;
415 
416  if (len == 0 || *str != '=')
417  return -1;
418  str++, len--;
419 
420  p = memchr (str, ',', len);
421  if (!p)
422  return -1;
423  p++;
424 
425  l = p - str;
426  if (len < l)
427  return -1;
428 
429  str = p;
430  len -= l;
431  }
432 
433  if (len == 0 || *str != 'p')
434  return -1;
435  str++, len--;
436 
437  if (len == 0 || *str != '=')
438  return -1;
439  str++, len--;
440 
441  /* Sanity check proof. */
442  if (memchr (str, '\0', len))
443  return -1;
444 
445  cl->proof = malloc (len + 1);
446  if (!cl->proof)
447  return -1;
448 
449  memcpy (cl->proof, str, len);
450  cl->proof[len] = '\0';
451 
452  if (!scram_valid_client_final (cl))
453  return -1;
454 
455  return 0;
456 }
457 
458 int
459 scram_parse_server_final (const char *str, size_t len,
460  struct scram_server_final *sl)
461 {
463 
464  /* Minimum client final string is 'v=ab=='. */
465  if (strnlen (str, len) < 6)
466  return -1;
467 
468  if (len == 0 || *str != 'v')
469  return -1;
470  str++, len--;
471 
472  if (len == 0 || *str != '=')
473  return -1;
474  str++, len--;
475 
476  /* Sanity check proof. */
477  if (memchr (str, '\0', len))
478  return -1;
479 
480  sl->verifier = malloc (len + 1);
481  if (!sl->verifier)
482  return -1;
483 
484  memcpy (sl->verifier, str, len);
485  sl->verifier[len] = '\0';
486 
487  if (!scram_valid_server_final (sl))
488  return -1;
489 
490  return 0;
491 }
int scram_parse_client_final(const char *str, size_t len, struct scram_client_final *cl)
Definition: scram/parser.c:329
int scram_parse_client_first(const char *str, size_t len, struct scram_client_first *cf)
Definition: scram/parser.c:76
int scram_parse_server_final(const char *str, size_t len, struct scram_server_final *sl)
Definition: scram/parser.c:459
int scram_parse_server_first(const char *str, size_t len, struct scram_server_first *sf)
Definition: scram/parser.c:218
bool scram_valid_client_first(struct scram_client_first *cf)
bool scram_valid_server_final(struct scram_server_final *sl)
bool scram_valid_server_first(struct scram_server_first *sf)
bool scram_valid_client_final(struct scram_client_final *cl)
void scram_free_server_first(struct scram_server_first *sf)
Definition: tokens.c:46
void scram_free_client_first(struct scram_client_first *cf)
Definition: tokens.c:35
void scram_free_server_final(struct scram_server_final *sl)
Definition: tokens.c:65
void scram_free_client_final(struct scram_client_final *cl)
Definition: tokens.c:55