gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

parser.c
Go to the documentation of this file.
1 /* parser.c --- SCRAM parser.
2  * Copyright (C) 2009-2021 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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 /* Get prototypes. */
28 #include "parser.h"
29 
30 /* Get malloc, free. */
31 #include <stdlib.h>
32 
33 /* Get memcpy, strlen. */
34 #include <string.h>
35 
36 /* Get validator. */
37 #include "validate.h"
38 
39 /* Get c_isalpha. */
40 #include "c-ctype.h"
41 
42 static char *
43 unescape (const char *str, size_t len)
44 {
45  char *out = malloc (len + 1);
46  char *p = out;
47 
48  if (!out)
49  return NULL;
50 
51  while (len > 0 && *str)
52  {
53  if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
54  {
55  *p++ = ',';
56  str += 3;
57  len -= 3;
58  }
59  else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
60  {
61  *p++ = '=';
62  str += 3;
63  len -= 3;
64  }
65  else
66  {
67  *p++ = *str;
68  str++;
69  len--;
70  }
71  }
72  *p = '\0';
73 
74  return out;
75 }
76 
77 int
78 scram_parse_client_first (const char *str, size_t len,
79  struct scram_client_first *cf)
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  if (!p)
194  return -1;
195 
196  l = p - str;
197  if (len < l)
198  return -1;
199 
200  cf->client_nonce = malloc (l + 1);
201  if (!cf->client_nonce)
202  return -1;
203 
204  memcpy (cf->client_nonce, str, l);
205  cf->client_nonce[l] = '\0';
206 
207  str = p;
208  len -= l;
209  }
210 
211  /* FIXME check that any extension fields follow valid syntax. */
212 
213  if (!scram_valid_client_first (cf))
214  return -1;
215 
216  return 0;
217 }
218 
219 int
220 scram_parse_server_first (const char *str, size_t len,
221  struct scram_server_first *sf)
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 {
332  /* Minimum client final string is 'c=biws,r=ab,p=ab=='. */
333  if (strnlen (str, len) < 18)
334  return -1;
335 
336  if (len == 0 || *str != 'c')
337  return -1;
338  str++, len--;
339 
340  if (len == 0 || *str != '=')
341  return -1;
342  str++, len--;
343 
344  {
345  const char *p;
346  size_t l;
347 
348  p = memchr (str, ',', len);
349  if (!p)
350  return -1;
351 
352  l = p - str;
353  if (len < l)
354  return -1;
355 
356  cl->cbind = malloc (l + 1);
357  if (!cl->cbind)
358  return -1;
359 
360  memcpy (cl->cbind, str, l);
361  cl->cbind[l] = '\0';
362 
363  str = p;
364  len -= l;
365  }
366 
367  if (len == 0 || *str != ',')
368  return -1;
369  str++, len--;
370 
371  if (len == 0 || *str != 'r')
372  return -1;
373  str++, len--;
374 
375  if (len == 0 || *str != '=')
376  return -1;
377  str++, len--;
378 
379  {
380  const char *p;
381  size_t l;
382 
383  p = memchr (str, ',', len);
384  if (!p)
385  return -1;
386 
387  l = p - str;
388  if (len < l)
389  return -1;
390 
391  cl->nonce = malloc (l + 1);
392  if (!cl->nonce)
393  return -1;
394 
395  memcpy (cl->nonce, str, l);
396  cl->nonce[l] = '\0';
397 
398  str = p;
399  len -= l;
400  }
401 
402  if (len == 0 || *str != ',')
403  return -1;
404  str++, len--;
405 
406  /* Ignore extensions. */
407  while (len > 0 && c_isalpha (*str) && *str != 'p')
408  {
409  const char *p;
410  size_t l;
411 
412  str++, len--;
413 
414  if (len == 0 || *str != '=')
415  return -1;
416  str++, len--;
417 
418  p = memchr (str, ',', len);
419  if (!p)
420  return -1;
421  p++;
422 
423  l = p - str;
424  if (len < l)
425  return -1;
426 
427  str = p;
428  len -= l;
429  }
430 
431  if (len == 0 || *str != 'p')
432  return -1;
433  str++, len--;
434 
435  if (len == 0 || *str != '=')
436  return -1;
437  str++, len--;
438 
439  /* Sanity check proof. */
440  if (memchr (str, '\0', len))
441  return -1;
442 
443  cl->proof = malloc (len + 1);
444  if (!cl->proof)
445  return -1;
446 
447  memcpy (cl->proof, str, len);
448  cl->proof[len] = '\0';
449 
450  if (!scram_valid_client_final (cl))
451  return -1;
452 
453  return 0;
454 }
455 
456 int
457 scram_parse_server_final (const char *str, size_t len,
458  struct scram_server_final *sl)
459 {
460  /* Minimum client final string is 'v=ab=='. */
461  if (strnlen (str, len) < 6)
462  return -1;
463 
464  if (len == 0 || *str != 'v')
465  return -1;
466  str++, len--;
467 
468  if (len == 0 || *str != '=')
469  return -1;
470  str++, len--;
471 
472  /* Sanity check proof. */
473  if (memchr (str, '\0', len))
474  return -1;
475 
476  sl->verifier = malloc (len + 1);
477  if (!sl->verifier)
478  return -1;
479 
480  memcpy (sl->verifier, str, len);
481  sl->verifier[len] = '\0';
482 
483  if (!scram_valid_server_final (sl))
484  return -1;
485 
486  return 0;
487 }
_GL_INLINE signed char c_isalpha(int c)
Definition: c-ctype.h:183
void * memchr(void const *s, int c_in, size_t n)
Definition: memchr.c:59
#define NULL
Definition: stddef.in.h:72
const char * p
Definition: mbrtowc-impl.h:42
int scram_parse_client_final(const char *str, size_t len, struct scram_client_final *cl)
Definition: parser.c:329
int scram_parse_client_first(const char *str, size_t len, struct scram_client_first *cf)
Definition: parser.c:78
int scram_parse_server_final(const char *str, size_t len, struct scram_server_final *sl)
Definition: parser.c:457
static char * unescape(const char *str, size_t len)
Definition: parser.c:43
int scram_parse_server_first(const char *str, size_t len, struct scram_server_first *sf)
Definition: parser.c:220
signed char scram_valid_client_final(struct scram_client_final *cl)
Definition: validate.c:106
signed char scram_valid_server_first(struct scram_server_first *sf)
Definition: validate.c:81
signed char scram_valid_server_final(struct scram_server_final *sl)
Definition: validate.c:136
signed char scram_valid_client_first(struct scram_client_first *cf)
Definition: validate.c:34
size_t strnlen(const char *string, size_t maxlen)
Definition: strnlen.c:26
char * proof
Definition: tokens.h:49
char * nonce
Definition: tokens.h:48
char * cbind
Definition: tokens.h:47
char * cbname
Definition: tokens.h:32
char * username
Definition: tokens.h:34
char * client_nonce
Definition: tokens.h:35
char * authzid
Definition: tokens.h:33
char * verifier
Definition: tokens.h:54
char * nonce
Definition: tokens.h:40