Branch data Line data Source code
1 : : /* parser.c --- SCRAM parser.
2 : : * Copyright (C) 2009-2012 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 : 66 : unescape (const char *str, size_t len)
44 : : {
45 : 66 : char *out = malloc (len + 1);
46 : 66 : char *p = out;
47 : :
48 [ - + ]: 66 : if (!out)
49 : 0 : return NULL;
50 : :
51 [ + + ][ + - ]: 390 : while (len > 0 && *str)
52 : : {
53 [ + + ][ + + ]: 324 : if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
[ + + ][ + - ]
54 : : {
55 : 44 : *p++ = ',';
56 : 44 : str += 3;
57 : 44 : len -= 3;
58 : : }
59 [ + + ][ + + ]: 280 : else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
[ + - ][ + - ]
60 : : {
61 : 40 : *p++ = '=';
62 : 40 : str += 3;
63 : 40 : len -= 3;
64 : : }
65 : : else
66 : : {
67 : 240 : *p++ = *str;
68 : 240 : str++;
69 : 240 : len--;
70 : : }
71 : : }
72 : 66 : *p = '\0';
73 : :
74 : 66 : return out;
75 : : }
76 : :
77 : : int
78 : 48 : 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 [ + + ]: 48 : if (strnlen (str, len) < 10)
83 : 4 : return -1;
84 : :
85 [ + - ][ + + ]: 44 : if (len == 0 || (*str != 'n' && *str != 'y' && *str != 'p'))
[ + + ][ - + ]
86 : 0 : return -1;
87 : 44 : cf->cbflag = *str;
88 : 44 : str++, len--;
89 : :
90 [ + + ]: 44 : if (cf->cbflag == 'p')
91 : : {
92 : : const char *p;
93 : :
94 [ + - ][ - + ]: 22 : if (len == 0 || *str != '=')
95 : 0 : return -1;
96 : 22 : str++, len--;
97 : :
98 : 22 : p = memchr (str, ',', len);
99 [ - + ]: 22 : if (!p)
100 : 0 : return -1;
101 : 22 : cf->cbname = malloc (p - str + 1);
102 [ - + ]: 22 : if (!cf->cbname)
103 : 0 : return -1;
104 : 22 : memcpy (cf->cbname, str, p - str);
105 : 22 : cf->cbname[p - str] = '\0';
106 : 22 : len -= (p - str);
107 : 22 : str += (p - str);
108 : : }
109 : :
110 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
111 : 0 : return -1;
112 : 44 : str++, len--;
113 : :
114 [ - + ]: 44 : if (len == 0)
115 : 0 : return -1;
116 [ + + ]: 44 : if (*str == 'a')
117 : : {
118 : : const char *p;
119 : : size_t l;
120 : :
121 : 22 : str++, len--;
122 [ + - ][ - + ]: 22 : if (len == 0 || *str != '=')
123 : 0 : return -1;
124 : 22 : str++, len--;
125 : :
126 : 22 : p = memchr (str, ',', len);
127 [ - + ]: 22 : if (!p)
128 : 0 : return -1;
129 : :
130 : 22 : l = p - str;
131 [ - + ]: 22 : if (len < l)
132 : 0 : return -1;
133 : :
134 : 22 : cf->authzid = unescape (str, l);
135 [ - + ]: 22 : if (!cf->authzid)
136 : 0 : return -1;
137 : :
138 : 22 : str = p;
139 : 22 : len -= l;
140 : : }
141 : :
142 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
143 : 0 : return -1;
144 : 44 : str++, len--;
145 : :
146 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'n')
147 : 0 : return -1;
148 : 44 : str++, len--;
149 : :
150 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
151 : 0 : return -1;
152 : 44 : str++, len--;
153 : :
154 : : {
155 : : const char *p;
156 : : size_t l;
157 : :
158 : 44 : p = memchr (str, ',', len);
159 [ - + ]: 44 : if (!p)
160 : 0 : return -1;
161 : :
162 : 44 : l = p - str;
163 [ - + ]: 44 : if (len < l)
164 : 0 : return -1;
165 : :
166 : 44 : cf->username = unescape (str, l);
167 [ - + ]: 44 : if (!cf->username)
168 : 0 : return -1;
169 : :
170 : 44 : str = p;
171 : 44 : len -= l;
172 : : }
173 : :
174 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
175 : 0 : return -1;
176 : 44 : str++, len--;
177 : :
178 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'r')
179 : 0 : return -1;
180 : 44 : str++, len--;
181 : :
182 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
183 : 0 : return -1;
184 : 44 : str++, len--;
185 : :
186 : : {
187 : : const char *p;
188 : : size_t l;
189 : :
190 : 44 : p = memchr (str, ',', len);
191 [ + + ]: 44 : if (!p)
192 : 42 : p = str + len;
193 [ - + ]: 44 : if (!p)
194 : 0 : return -1;
195 : :
196 : 44 : l = p - str;
197 [ - + ]: 44 : if (len < l)
198 : 0 : return -1;
199 : :
200 : 44 : cf->client_nonce = malloc (l + 1);
201 [ - + ]: 44 : if (!cf->client_nonce)
202 : 0 : return -1;
203 : :
204 : 44 : memcpy (cf->client_nonce, str, l);
205 : 44 : cf->client_nonce[l] = '\0';
206 : :
207 : 44 : str = p;
208 : 44 : len -= l;
209 : : }
210 : :
211 : : /* FIXME check that any extension fields follow valid syntax. */
212 : :
213 [ - + ]: 44 : if (scram_valid_client_first (cf) < 0)
214 : 0 : return -1;
215 : :
216 : 48 : return 0;
217 : : }
218 : :
219 : : int
220 : 44 : 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 [ - + ]: 44 : if (strnlen (str, len) < 15)
225 : 0 : return -1;
226 : :
227 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'r')
228 : 0 : return -1;
229 : 44 : str++, len--;
230 : :
231 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
232 : 0 : return -1;
233 : 44 : str++, len--;
234 : :
235 : : {
236 : : const char *p;
237 : : size_t l;
238 : :
239 : 44 : p = memchr (str, ',', len);
240 [ - + ]: 44 : if (!p)
241 : 0 : return -1;
242 : :
243 : 44 : l = p - str;
244 [ - + ]: 44 : if (len < l)
245 : 0 : return -1;
246 : :
247 : 44 : sf->nonce = malloc (l + 1);
248 [ - + ]: 44 : if (!sf->nonce)
249 : 0 : return -1;
250 : :
251 : 44 : memcpy (sf->nonce, str, l);
252 : 44 : sf->nonce[l] = '\0';
253 : :
254 : 44 : str = p;
255 : 44 : len -= l;
256 : : }
257 : :
258 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
259 : 0 : return -1;
260 : 44 : str++, len--;
261 : :
262 [ + - ][ - + ]: 44 : if (len == 0 || *str != 's')
263 : 0 : return -1;
264 : 44 : str++, len--;
265 : :
266 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
267 : 0 : return -1;
268 : 44 : str++, len--;
269 : :
270 : : {
271 : : const char *p;
272 : : size_t l;
273 : :
274 : 44 : p = memchr (str, ',', len);
275 [ - + ]: 44 : if (!p)
276 : 0 : return -1;
277 : :
278 : 44 : l = p - str;
279 [ - + ]: 44 : if (len < l)
280 : 0 : return -1;
281 : :
282 : 44 : sf->salt = malloc (l + 1);
283 [ - + ]: 44 : if (!sf->salt)
284 : 0 : return -1;
285 : :
286 : 44 : memcpy (sf->salt, str, l);
287 : 44 : sf->salt[l] = '\0';
288 : :
289 : 44 : str = p;
290 : 44 : len -= l;
291 : : }
292 : :
293 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
294 : 0 : return -1;
295 : 44 : str++, len--;
296 : :
297 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'i')
298 : 0 : return -1;
299 : 44 : str++, len--;
300 : :
301 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
302 : 0 : return -1;
303 : 44 : str++, len--;
304 : :
305 : 44 : sf->iter = 0;
306 [ + + ][ + - ]: 220 : for (; len > 0 && *str >= '0' && *str <= '9'; str++, len--)
[ + - ]
307 : : {
308 : 176 : size_t last_iter = sf->iter;
309 : :
310 : 176 : sf->iter = sf->iter * 10 + (*str - '0');
311 : :
312 : : /* Protect against wrap arounds. */
313 [ - + ]: 176 : if (sf->iter < last_iter)
314 : 0 : return -1;
315 : : }
316 : :
317 [ - + ][ # # ]: 44 : if (len > 0 && *str != ',')
318 : 0 : return -1;
319 : :
320 : : /* FIXME check that any extension fields follow valid syntax. */
321 : :
322 [ - + ]: 44 : if (scram_valid_server_first (sf) < 0)
323 : 0 : return -1;
324 : :
325 : 44 : return 0;
326 : : }
327 : :
328 : : int
329 : 44 : 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 [ - + ]: 44 : if (strnlen (str, len) < 18)
334 : 0 : return -1;
335 : :
336 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'c')
337 : 0 : return -1;
338 : 44 : str++, len--;
339 : :
340 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
341 : 0 : return -1;
342 : 44 : str++, len--;
343 : :
344 : : {
345 : : const char *p;
346 : : size_t l;
347 : :
348 : 44 : p = memchr (str, ',', len);
349 [ - + ]: 44 : if (!p)
350 : 0 : return -1;
351 : :
352 : 44 : l = p - str;
353 [ - + ]: 44 : if (len < l)
354 : 0 : return -1;
355 : :
356 : 44 : cl->cbind = malloc (l + 1);
357 [ - + ]: 44 : if (!cl->cbind)
358 : 0 : return -1;
359 : :
360 : 44 : memcpy (cl->cbind, str, l);
361 : 44 : cl->cbind[l] = '\0';
362 : :
363 : 44 : str = p;
364 : 44 : len -= l;
365 : : }
366 : :
367 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
368 : 0 : return -1;
369 : 44 : str++, len--;
370 : :
371 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'r')
372 : 0 : return -1;
373 : 44 : str++, len--;
374 : :
375 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
376 : 0 : return -1;
377 : 44 : str++, len--;
378 : :
379 : : {
380 : : const char *p;
381 : : size_t l;
382 : :
383 : 44 : p = memchr (str, ',', len);
384 [ - + ]: 44 : if (!p)
385 : 0 : return -1;
386 : :
387 : 44 : l = p - str;
388 [ - + ]: 44 : if (len < l)
389 : 0 : return -1;
390 : :
391 : 44 : cl->nonce = malloc (l + 1);
392 [ - + ]: 44 : if (!cl->nonce)
393 : 0 : return -1;
394 : :
395 : 44 : memcpy (cl->nonce, str, l);
396 : 44 : cl->nonce[l] = '\0';
397 : :
398 : 44 : str = p;
399 : 44 : len -= l;
400 : : }
401 : :
402 [ + - ][ - + ]: 44 : if (len == 0 || *str != ',')
403 : 0 : return -1;
404 : 44 : str++, len--;
405 : :
406 : : /* Ignore extensions. */
407 [ + - ][ + - ]: 48 : while (len > 0 && c_isalpha (*str) && *str != 'p')
[ + + ]
408 : : {
409 : : const char *p;
410 : : size_t l;
411 : :
412 : 4 : str++, len--;
413 : :
414 [ + - ][ - + ]: 4 : if (len == 0 || *str != '=')
415 : 0 : return -1;
416 : 4 : str++, len--;
417 : :
418 : 4 : p = memchr (str, ',', len);
419 [ - + ]: 4 : if (!p)
420 : 0 : return -1;
421 : 4 : p++;
422 : :
423 : 4 : l = p - str;
424 [ - + ]: 4 : if (len < l)
425 : 0 : return -1;
426 : :
427 : 4 : str = p;
428 : 4 : len -= l;
429 : : }
430 : :
431 [ + - ][ - + ]: 44 : if (len == 0 || *str != 'p')
432 : 0 : return -1;
433 : 44 : str++, len--;
434 : :
435 [ + - ][ - + ]: 44 : if (len == 0 || *str != '=')
436 : 0 : return -1;
437 : 44 : str++, len--;
438 : :
439 : : /* Sanity check proof. */
440 [ - + ]: 44 : if (memchr (str, '\0', len))
441 : 0 : return -1;
442 : :
443 : 44 : cl->proof = malloc (len + 1);
444 [ - + ]: 44 : if (!cl->proof)
445 : 0 : return -1;
446 : :
447 : 44 : memcpy (cl->proof, str, len);
448 : 44 : cl->proof[len] = '\0';
449 : :
450 [ - + ]: 44 : if (scram_valid_client_final (cl) < 0)
451 : 0 : return -1;
452 : :
453 : 44 : return 0;
454 : : }
455 : :
456 : : int
457 : 35 : 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 [ - + ]: 35 : if (strnlen (str, len) < 6)
462 : 0 : return -1;
463 : :
464 [ + - ][ - + ]: 35 : if (len == 0 || *str != 'v')
465 : 0 : return -1;
466 : 35 : str++, len--;
467 : :
468 [ + - ][ - + ]: 35 : if (len == 0 || *str != '=')
469 : 0 : return -1;
470 : 35 : str++, len--;
471 : :
472 : : /* Sanity check proof. */
473 [ - + ]: 35 : if (memchr (str, '\0', len))
474 : 0 : return -1;
475 : :
476 : 35 : sl->verifier = malloc (len + 1);
477 [ - + ]: 35 : if (!sl->verifier)
478 : 0 : return -1;
479 : :
480 : 35 : memcpy (sl->verifier, str, len);
481 : 35 : sl->verifier[len] = '\0';
482 : :
483 [ - + ]: 35 : if (scram_valid_server_final (sl) < 0)
484 : 0 : return -1;
485 : :
486 : 35 : return 0;
487 : : }
|