1 /*
2 * JavaScript Object Notation (JSON) parser (RFC7159)
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "base64.h"
13 #include "json.h"
14
15 #define JSON_MAX_DEPTH 10
16 #define JSON_MAX_TOKENS 500
17
18
json_escape_string(char * txt,size_t maxlen,const char * data,size_t len)19 void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
20 {
21 char *end = txt + maxlen;
22 size_t i;
23
24 for (i = 0; i < len; i++) {
25 if (txt + 4 >= end)
26 break;
27
28 switch (data[i]) {
29 case '\"':
30 *txt++ = '\\';
31 *txt++ = '\"';
32 break;
33 case '\\':
34 *txt++ = '\\';
35 *txt++ = '\\';
36 break;
37 case '\n':
38 *txt++ = '\\';
39 *txt++ = 'n';
40 break;
41 case '\r':
42 *txt++ = '\\';
43 *txt++ = 'r';
44 break;
45 case '\t':
46 *txt++ = '\\';
47 *txt++ = 't';
48 break;
49 default:
50 if (data[i] >= 32 && data[i] <= 126) {
51 *txt++ = data[i];
52 } else {
53 txt += os_snprintf(txt, end - txt, "\\u%04x",
54 data[i]);
55 }
56 break;
57 }
58 }
59
60 *txt = '\0';
61 }
62
63
json_parse_string(const char ** json_pos,const char * end)64 static char * json_parse_string(const char **json_pos, const char *end)
65 {
66 const char *pos = *json_pos;
67 char *str, *spos, *s_end;
68 size_t max_len, buf_len;
69 u8 bin[2];
70
71 pos++; /* skip starting quote */
72
73 max_len = end - pos + 1;
74 buf_len = max_len > 10 ? 10 : max_len;
75 str = os_malloc(buf_len);
76 if (!str)
77 return NULL;
78 spos = str;
79 s_end = str + buf_len;
80
81 for (; pos < end; pos++) {
82 if (buf_len < max_len && s_end - spos < 3) {
83 char *tmp;
84 int idx;
85
86 idx = spos - str;
87 buf_len *= 2;
88 if (buf_len > max_len)
89 buf_len = max_len;
90 tmp = os_realloc(str, buf_len);
91 if (!tmp)
92 goto fail;
93 str = tmp;
94 spos = str + idx;
95 s_end = str + buf_len;
96 }
97
98 switch (*pos) {
99 case '\"': /* end string */
100 *spos = '\0';
101 /* caller will move to the next position */
102 *json_pos = pos;
103 return str;
104 case '\\':
105 pos++;
106 switch (*pos) {
107 case '"':
108 case '\\':
109 case '/':
110 *spos++ = *pos;
111 break;
112 case 'n':
113 *spos++ = '\n';
114 break;
115 case 'r':
116 *spos++ = '\r';
117 break;
118 case 't':
119 *spos++ = '\t';
120 break;
121 case 'u':
122 if (end - pos < 5 ||
123 hexstr2bin(pos + 1, bin, 2) < 0 ||
124 bin[1] == 0x00) {
125 wpa_printf(MSG_DEBUG,
126 "JSON: Invalid \\u escape");
127 goto fail;
128 }
129 if (bin[0] == 0x00) {
130 *spos++ = bin[1];
131 } else {
132 *spos++ = bin[0];
133 *spos++ = bin[1];
134 }
135 pos += 4;
136 break;
137 default:
138 wpa_printf(MSG_DEBUG,
139 "JSON: Unknown escape '%c'", *pos);
140 goto fail;
141 }
142 break;
143 default:
144 *spos++ = *pos;
145 break;
146 }
147 }
148
149 fail:
150 os_free(str);
151 return NULL;
152 }
153
154
json_parse_number(const char ** json_pos,const char * end,int * ret_val)155 static int json_parse_number(const char **json_pos, const char *end,
156 int *ret_val)
157 {
158 const char *pos = *json_pos;
159 size_t len;
160 char *str;
161
162 for (; pos < end; pos++) {
163 if (*pos != '-' && (*pos < '0' || *pos > '9')) {
164 pos--;
165 break;
166 }
167 }
168 if (pos < *json_pos)
169 return -1;
170 len = pos - *json_pos + 1;
171 str = os_malloc(len + 1);
172 if (!str)
173 return -1;
174 os_memcpy(str, *json_pos, len);
175 str[len] = '\0';
176
177 *ret_val = atoi(str);
178 os_free(str);
179 *json_pos = pos;
180 return 0;
181 }
182
183
json_check_tree_state(struct json_token * token)184 static int json_check_tree_state(struct json_token *token)
185 {
186 if (!token)
187 return 0;
188 if (json_check_tree_state(token->child) < 0 ||
189 json_check_tree_state(token->sibling) < 0)
190 return -1;
191 if (token->state != JSON_COMPLETED) {
192 wpa_printf(MSG_DEBUG,
193 "JSON: Unexpected token state %d (name=%s type=%d)",
194 token->state, token->name ? token->name : "N/A",
195 token->type);
196 return -1;
197 }
198 return 0;
199 }
200
201
json_alloc_token(unsigned int * tokens)202 static struct json_token * json_alloc_token(unsigned int *tokens)
203 {
204 (*tokens)++;
205 if (*tokens > JSON_MAX_TOKENS) {
206 wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
207 return NULL;
208 }
209 return os_zalloc(sizeof(struct json_token));
210 }
211
212
json_parse(const char * data,size_t data_len)213 struct json_token * json_parse(const char *data, size_t data_len)
214 {
215 struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
216 const char *pos, *end;
217 char *str;
218 int num;
219 unsigned int depth = 0;
220 unsigned int tokens = 0;
221
222 pos = data;
223 end = data + data_len;
224
225 for (; pos < end; pos++) {
226 switch (*pos) {
227 case '[': /* start array */
228 case '{': /* start object */
229 if (!curr_token) {
230 token = json_alloc_token(&tokens);
231 if (!token)
232 goto fail;
233 } else if (curr_token->state == JSON_WAITING_VALUE) {
234 token = curr_token;
235 } else if (curr_token->parent &&
236 curr_token->parent->type == JSON_ARRAY &&
237 curr_token->parent->state == JSON_STARTED &&
238 curr_token->state == JSON_EMPTY) {
239 token = curr_token;
240 } else {
241 wpa_printf(MSG_DEBUG,
242 "JSON: Invalid state for start array/object");
243 goto fail;
244 }
245 depth++;
246 if (depth > JSON_MAX_DEPTH) {
247 wpa_printf(MSG_DEBUG,
248 "JSON: Max depth exceeded");
249 goto fail;
250 }
251 token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
252 token->state = JSON_STARTED;
253 token->child = json_alloc_token(&tokens);
254 if (!token->child)
255 goto fail;
256 curr_token = token->child;
257 curr_token->parent = token;
258 curr_token->state = JSON_EMPTY;
259 break;
260 case ']': /* end array */
261 case '}': /* end object */
262 if (!curr_token || !curr_token->parent ||
263 curr_token->parent->state != JSON_STARTED) {
264 wpa_printf(MSG_DEBUG,
265 "JSON: Invalid state for end array/object");
266 goto fail;
267 }
268 depth--;
269 curr_token = curr_token->parent;
270 if ((*pos == ']' &&
271 curr_token->type != JSON_ARRAY) ||
272 (*pos == '}' &&
273 curr_token->type != JSON_OBJECT)) {
274 wpa_printf(MSG_DEBUG,
275 "JSON: Array/Object mismatch");
276 goto fail;
277 }
278 if (curr_token->child->state == JSON_EMPTY &&
279 !curr_token->child->child &&
280 !curr_token->child->sibling) {
281 /* Remove pending child token since the
282 * array/object was empty. */
283 json_free(curr_token->child);
284 curr_token->child = NULL;
285 }
286 curr_token->state = JSON_COMPLETED;
287 break;
288 case '\"': /* string */
289 str = json_parse_string(&pos, end);
290 if (!str)
291 goto fail;
292 if (!curr_token) {
293 token = json_alloc_token(&tokens);
294 if (!token)
295 goto fail;
296 token->type = JSON_STRING;
297 token->string = str;
298 token->state = JSON_COMPLETED;
299 } else if (curr_token->parent &&
300 curr_token->parent->type == JSON_ARRAY &&
301 curr_token->parent->state == JSON_STARTED &&
302 curr_token->state == JSON_EMPTY) {
303 curr_token->string = str;
304 curr_token->state = JSON_COMPLETED;
305 curr_token->type = JSON_STRING;
306 wpa_printf(MSG_MSGDUMP,
307 "JSON: String value: '%s'",
308 curr_token->string);
309 } else if (curr_token->state == JSON_EMPTY) {
310 curr_token->type = JSON_VALUE;
311 curr_token->name = str;
312 curr_token->state = JSON_STARTED;
313 } else if (curr_token->state == JSON_WAITING_VALUE) {
314 curr_token->string = str;
315 curr_token->state = JSON_COMPLETED;
316 curr_token->type = JSON_STRING;
317 wpa_printf(MSG_MSGDUMP,
318 "JSON: String value: '%s' = '%s'",
319 curr_token->name,
320 curr_token->string);
321 } else {
322 wpa_printf(MSG_DEBUG,
323 "JSON: Invalid state for a string");
324 os_free(str);
325 goto fail;
326 }
327 break;
328 case ' ':
329 case '\t':
330 case '\r':
331 case '\n':
332 /* ignore whitespace */
333 break;
334 case ':': /* name/value separator */
335 if (!curr_token || curr_token->state != JSON_STARTED)
336 goto fail;
337 curr_token->state = JSON_WAITING_VALUE;
338 break;
339 case ',': /* member separator */
340 if (!curr_token)
341 goto fail;
342 curr_token->sibling = json_alloc_token(&tokens);
343 if (!curr_token->sibling)
344 goto fail;
345 curr_token->sibling->parent = curr_token->parent;
346 curr_token = curr_token->sibling;
347 curr_token->state = JSON_EMPTY;
348 break;
349 case 't': /* true */
350 case 'f': /* false */
351 case 'n': /* null */
352 if (!((end - pos >= 4 &&
353 os_strncmp(pos, "true", 4) == 0) ||
354 (end - pos >= 5 &&
355 os_strncmp(pos, "false", 5) == 0) ||
356 (end - pos >= 4 &&
357 os_strncmp(pos, "null", 4) == 0))) {
358 wpa_printf(MSG_DEBUG,
359 "JSON: Invalid literal name");
360 goto fail;
361 }
362 if (!curr_token) {
363 token = json_alloc_token(&tokens);
364 if (!token)
365 goto fail;
366 curr_token = token;
367 } else if (curr_token->state == JSON_WAITING_VALUE) {
368 wpa_printf(MSG_MSGDUMP,
369 "JSON: Literal name: '%s' = %c",
370 curr_token->name, *pos);
371 } else if (curr_token->parent &&
372 curr_token->parent->type == JSON_ARRAY &&
373 curr_token->parent->state == JSON_STARTED &&
374 curr_token->state == JSON_EMPTY) {
375 wpa_printf(MSG_MSGDUMP,
376 "JSON: Literal name: %c", *pos);
377 } else {
378 wpa_printf(MSG_DEBUG,
379 "JSON: Invalid state for a literal name");
380 goto fail;
381 }
382 switch (*pos) {
383 case 't':
384 curr_token->type = JSON_BOOLEAN;
385 curr_token->number = 1;
386 pos += 3;
387 break;
388 case 'f':
389 curr_token->type = JSON_BOOLEAN;
390 curr_token->number = 0;
391 pos += 4;
392 break;
393 case 'n':
394 curr_token->type = JSON_NULL;
395 pos += 3;
396 break;
397 }
398 curr_token->state = JSON_COMPLETED;
399 break;
400 case '-':
401 case '0':
402 case '1':
403 case '2':
404 case '3':
405 case '4':
406 case '5':
407 case '6':
408 case '7':
409 case '8':
410 case '9':
411 /* number */
412 if (json_parse_number(&pos, end, &num) < 0)
413 goto fail;
414 if (!curr_token) {
415 token = json_alloc_token(&tokens);
416 if (!token)
417 goto fail;
418 token->type = JSON_NUMBER;
419 token->number = num;
420 token->state = JSON_COMPLETED;
421 } else if (curr_token->state == JSON_WAITING_VALUE) {
422 curr_token->number = num;
423 curr_token->state = JSON_COMPLETED;
424 curr_token->type = JSON_NUMBER;
425 wpa_printf(MSG_MSGDUMP,
426 "JSON: Number value: '%s' = '%d'",
427 curr_token->name,
428 curr_token->number);
429 } else if (curr_token->parent &&
430 curr_token->parent->type == JSON_ARRAY &&
431 curr_token->parent->state == JSON_STARTED &&
432 curr_token->state == JSON_EMPTY) {
433 curr_token->number = num;
434 curr_token->state = JSON_COMPLETED;
435 curr_token->type = JSON_NUMBER;
436 wpa_printf(MSG_MSGDUMP,
437 "JSON: Number value: %d",
438 curr_token->number);
439 } else {
440 wpa_printf(MSG_DEBUG,
441 "JSON: Invalid state for a number");
442 goto fail;
443 }
444 break;
445 default:
446 wpa_printf(MSG_DEBUG,
447 "JSON: Unexpected JSON character: %c", *pos);
448 goto fail;
449 }
450
451 if (!root)
452 root = token;
453 if (!curr_token)
454 curr_token = token;
455 }
456
457 if (json_check_tree_state(root) < 0) {
458 wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
459 goto fail;
460 }
461
462 return root;
463 fail:
464 wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
465 json_free(root);
466 return NULL;
467 }
468
469
json_free(struct json_token * json)470 void json_free(struct json_token *json)
471 {
472 if (!json)
473 return;
474 json_free(json->child);
475 json_free(json->sibling);
476 os_free(json->name);
477 os_free(json->string);
478 os_free(json);
479 }
480
481
json_get_member(struct json_token * json,const char * name)482 struct json_token * json_get_member(struct json_token *json, const char *name)
483 {
484 struct json_token *token, *ret = NULL;
485
486 if (!json || json->type != JSON_OBJECT)
487 return NULL;
488 /* Return last matching entry */
489 for (token = json->child; token; token = token->sibling) {
490 if (token->name && os_strcmp(token->name, name) == 0)
491 ret = token;
492 }
493 return ret;
494 }
495
496
json_get_member_base64url(struct json_token * json,const char * name)497 struct wpabuf * json_get_member_base64url(struct json_token *json,
498 const char *name)
499 {
500 struct json_token *token;
501 unsigned char *buf;
502 size_t buflen;
503 struct wpabuf *ret;
504
505 token = json_get_member(json, name);
506 if (!token || token->type != JSON_STRING)
507 return NULL;
508 buf = base64_url_decode((const unsigned char *) token->string,
509 os_strlen(token->string), &buflen);
510 if (!buf)
511 return NULL;
512 ret = wpabuf_alloc_ext_data(buf, buflen);
513 if (!ret)
514 os_free(buf);
515
516 return ret;
517 }
518
519
json_type_str(enum json_type type)520 static const char * json_type_str(enum json_type type)
521 {
522 switch (type) {
523 case JSON_VALUE:
524 return "VALUE";
525 case JSON_OBJECT:
526 return "OBJECT";
527 case JSON_ARRAY:
528 return "ARRAY";
529 case JSON_STRING:
530 return "STRING";
531 case JSON_NUMBER:
532 return "NUMBER";
533 case JSON_BOOLEAN:
534 return "BOOLEAN";
535 case JSON_NULL:
536 return "NULL";
537 }
538 return "??";
539 }
540
541
json_print_token(struct json_token * token,int depth,char * buf,size_t buflen)542 static void json_print_token(struct json_token *token, int depth,
543 char *buf, size_t buflen)
544 {
545 size_t len;
546 int ret;
547
548 if (!token)
549 return;
550 len = os_strlen(buf);
551 ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
552 depth, json_type_str(token->type),
553 token->name ? token->name : "");
554 if (os_snprintf_error(buflen - len, ret)) {
555 buf[len] = '\0';
556 return;
557 }
558 json_print_token(token->child, depth + 1, buf, buflen);
559 json_print_token(token->sibling, depth, buf, buflen);
560 }
561
562
json_print_tree(struct json_token * root,char * buf,size_t buflen)563 void json_print_tree(struct json_token *root, char *buf, size_t buflen)
564 {
565 buf[0] = '\0';
566 json_print_token(root, 1, buf, buflen);
567 }
568