1 /* $Id: json.c,v 1.5 2016/09/13 17:13:37 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <assert.h> 19 #include <err.h> 20 #include <stdarg.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include "jsmn.h" 27 #include "extern.h" 28 29 struct jsmnp; 30 31 /* 32 * A node in the JSMN parse tree. 33 * Each of this corresponds to an object in the original JSMN token 34 * list, although the contents have been extracted properly. 35 */ 36 struct jsmnn { 37 struct parse *p; /* parser object */ 38 union { 39 char *str; /* JSMN_PRIMITIVE, JSMN_STRING */ 40 struct jsmnp *obj; /* JSMN_OBJECT */ 41 struct jsmnn **array; /* JSMN_ARRAY */ 42 } d; 43 size_t fields; /* entries in "d" */ 44 jsmntype_t type; /* type of node */ 45 }; 46 47 /* 48 * Objects consist of node pairs: the left-hand side (before the colon) 49 * and the right-hand side---the data. 50 */ 51 struct jsmnp { 52 struct jsmnn *lhs; /* left of colon */ 53 struct jsmnn *rhs; /* right of colon */ 54 }; 55 56 /* 57 * Object for converting the JSMN token array into a tree. 58 */ 59 struct parse { 60 struct jsmnn *nodes; /* all nodes */ 61 size_t cur; /* current number */ 62 size_t max; /* nodes in "nodes" */ 63 }; 64 65 /* 66 * Recursive part for convertin a JSMN token array into a tree. 67 * See "example/jsondump.c" for its construction (it's the same except 68 * for how it handles allocation errors). 69 */ 70 static ssize_t 71 build(struct parse *parse, struct jsmnn **np, 72 jsmntok_t *t, const char *js, size_t sz) 73 { 74 size_t i, j; 75 struct jsmnn *n; 76 ssize_t tmp; 77 78 if (0 == sz) 79 return (0); 80 81 assert(parse->cur < parse->max); 82 n = *np = &parse->nodes[parse->cur++]; 83 n->p = parse; 84 n->type = t->type; 85 86 switch (t->type) { 87 case JSMN_STRING: 88 /* FALLTHROUGH */ 89 case JSMN_PRIMITIVE: 90 n->fields = 1; 91 n->d.str = strndup 92 (js + t->start, 93 t->end - t->start); 94 if (NULL == n->d.str) 95 break; 96 return (1); 97 case JSMN_OBJECT: 98 n->fields = t->size; 99 n->d.obj = calloc(n->fields, 100 sizeof(struct jsmnp)); 101 if (NULL == n->d.obj) 102 break; 103 for (i = j = 0; i < (size_t)t->size; i++) { 104 tmp = build(parse, 105 &n->d.obj[i].lhs, 106 t + 1 + j, js, sz - j); 107 if (tmp < 0) 108 break; 109 j += tmp; 110 tmp = build(parse, 111 &n->d.obj[i].rhs, 112 t + 1 + j, js, sz - j); 113 if (tmp < 0) 114 break; 115 j += tmp; 116 } 117 if (i < (size_t)t->size) 118 break; 119 return (j + 1); 120 case JSMN_ARRAY: 121 n->fields = t->size; 122 n->d.array = calloc(n->fields, 123 sizeof(struct jsmnn *)); 124 if (NULL == n->d.array) 125 break; 126 for (i = j = 0; i < (size_t)t->size; i++) { 127 tmp = build(parse, 128 &n->d.array[i], 129 t + 1 + j, js, sz - j); 130 if (tmp < 0) 131 break; 132 j += tmp; 133 } 134 if (i < (size_t)t->size) 135 break; 136 return (j + 1); 137 default: 138 break; 139 } 140 141 return (-1); 142 } 143 144 /* 145 * Fully free up a parse sequence. 146 * This handles all nodes sequentially, not recursively. 147 */ 148 static void 149 jsmnparse_free(struct parse *p) 150 { 151 size_t i; 152 153 if (NULL == p) 154 return; 155 for (i = 0; i < p->max; i++) 156 if (JSMN_ARRAY == p->nodes[i].type) 157 free(p->nodes[i].d.array); 158 else if (JSMN_OBJECT == p->nodes[i].type) 159 free(p->nodes[i].d.obj); 160 else if (JSMN_PRIMITIVE == p->nodes[i].type) 161 free(p->nodes[i].d.str); 162 else if (JSMN_STRING == p->nodes[i].type) 163 free(p->nodes[i].d.str); 164 free(p->nodes); 165 free(p); 166 } 167 168 /* 169 * Allocate a tree representation of "t". 170 * This returns NULL on allocation failure or when sz is zero, in which 171 * case all resources allocated along the way are freed already. 172 */ 173 static struct jsmnn * 174 jsmntree_alloc(jsmntok_t *t, const char *js, size_t sz) 175 { 176 struct jsmnn *first; 177 struct parse *p; 178 179 if (0 == sz) 180 return (NULL); 181 182 p = calloc(1, sizeof(struct parse)); 183 if (NULL == p) 184 return (NULL); 185 186 p->max = sz; 187 p->nodes = calloc(p->max, sizeof(struct jsmnn)); 188 if (NULL == p->nodes) { 189 free(p); 190 return (NULL); 191 } 192 193 if (build(p, &first, t, js, sz) < 0) { 194 jsmnparse_free(p); 195 first = NULL; 196 } 197 198 return (first); 199 } 200 201 /* 202 * Call through to free parse contents. 203 */ 204 void 205 json_free(struct jsmnn *first) 206 { 207 208 if (NULL != first) 209 jsmnparse_free(first->p); 210 } 211 212 /* 213 * Just check that the array object is in fact an object. 214 */ 215 static struct jsmnn * 216 json_getarrayobj(struct jsmnn *n) 217 { 218 219 return (JSMN_OBJECT != n->type ? NULL : n); 220 } 221 222 /* 223 * Extract an array from the returned JSON object, making sure that it's 224 * the correct type. 225 * Returns NULL on failure. 226 */ 227 static struct jsmnn * 228 json_getarray(struct jsmnn *n, const char *name) 229 { 230 size_t i; 231 232 if (JSMN_OBJECT != n->type) 233 return (NULL); 234 for (i = 0; i < n->fields; i++) { 235 if (JSMN_STRING != n->d.obj[i].lhs->type && 236 JSMN_PRIMITIVE != n->d.obj[i].lhs->type) 237 continue; 238 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 239 continue; 240 break; 241 } 242 if (i == n->fields) 243 return (NULL); 244 if (JSMN_ARRAY != n->d.obj[i].rhs->type) 245 return (NULL); 246 return (n->d.obj[i].rhs); 247 } 248 249 /* 250 * Extract a single string from the returned JSON object, making sure 251 * that it's the correct type. 252 * Returns NULL on failure. 253 */ 254 static char * 255 json_getstr(struct jsmnn *n, const char *name) 256 { 257 size_t i; 258 char *cp; 259 260 if (JSMN_OBJECT != n->type) 261 return (NULL); 262 for (i = 0; i < n->fields; i++) { 263 if (JSMN_STRING != n->d.obj[i].lhs->type && 264 JSMN_PRIMITIVE != n->d.obj[i].lhs->type) 265 continue; 266 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 267 continue; 268 break; 269 } 270 if (i == n->fields) 271 return (NULL); 272 if (JSMN_STRING != n->d.obj[i].rhs->type && 273 JSMN_PRIMITIVE != n->d.obj[i].rhs->type) 274 return (NULL); 275 276 cp = strdup(n->d.obj[i].rhs->d.str); 277 if (NULL == cp) 278 warn("strdup"); 279 return (cp); 280 } 281 282 /* 283 * Completely free the challenge response body. 284 */ 285 void 286 json_free_challenge(struct chng *p) 287 { 288 289 free(p->uri); 290 free(p->token); 291 p->uri = p->token = NULL; 292 } 293 294 /* 295 * Parse the response from the ACME server when we're waiting to see 296 * whether the challenge has been ok. 297 */ 298 int 299 json_parse_response(struct jsmnn *n) 300 { 301 char *resp; 302 int rc; 303 304 if (NULL == n) 305 return (-1); 306 if (NULL == (resp = json_getstr(n, "status"))) 307 return (-1); 308 309 if (0 == strcmp(resp, "valid")) 310 rc = 1; 311 else if (0 == strcmp(resp, "pending")) 312 rc = 0; 313 else 314 rc = -1; 315 316 free(resp); 317 return (rc); 318 } 319 320 /* 321 * Parse the response from a new-authz, which consists of challenge 322 * information, into a structure. 323 * We only care about the HTTP-01 response. 324 */ 325 int 326 json_parse_challenge(struct jsmnn *n, struct chng *p) 327 { 328 struct jsmnn *array, *obj; 329 size_t i; 330 int rc; 331 char *type; 332 333 if (NULL == n) 334 return (0); 335 336 array = json_getarray(n, "challenges"); 337 if (NULL == array) 338 return (0); 339 340 for (i = 0; i < array->fields; i++) { 341 obj = json_getarrayobj(array->d.array[i]); 342 if (NULL == obj) 343 continue; 344 type = json_getstr(obj, "type"); 345 if (NULL == type) 346 continue; 347 rc = strcmp(type, "http-01"); 348 free(type); 349 if (rc) 350 continue; 351 p->uri = json_getstr(obj, "uri"); 352 p->token = json_getstr(obj, "token"); 353 return (NULL != p->uri && NULL != p->token); 354 } 355 356 return (0); 357 } 358 359 /* 360 * Extract the CA paths from the JSON response object. 361 * Return zero on failure, non-zero on success. 362 */ 363 int 364 json_parse_capaths(struct jsmnn *n, struct capaths *p) 365 { 366 367 if (NULL == n) 368 return (0); 369 370 p->newauthz = json_getstr(n, "new-authz"); 371 p->newcert = json_getstr(n, "new-cert"); 372 p->newreg = json_getstr(n, "new-reg"); 373 p->revokecert = json_getstr(n, "revoke-cert"); 374 375 return (NULL != p->newauthz && NULL != p->newcert && 376 NULL != p->newreg && NULL != p->revokecert); 377 } 378 379 /* 380 * Free up all of our CA-noted paths (which may all be NULL). 381 */ 382 void 383 json_free_capaths(struct capaths *p) 384 { 385 386 free(p->newauthz); 387 free(p->newcert); 388 free(p->newreg); 389 free(p->revokecert); 390 memset(p, 0, sizeof(struct capaths)); 391 } 392 393 /* 394 * Parse an HTTP response body from a buffer of size "sz". 395 * Returns an opaque pointer on success, otherwise NULL on error. 396 */ 397 struct jsmnn * 398 json_parse(const char *buf, size_t sz) 399 { 400 struct jsmnn *n; 401 jsmn_parser p; 402 jsmntok_t *tok; 403 int r; 404 size_t tokcount; 405 406 jsmn_init(&p); 407 tokcount = 128; 408 409 /* Do this until we don't need any more tokens. */ 410 again: 411 tok = calloc(tokcount, sizeof(jsmntok_t)); 412 if (NULL == tok) { 413 warn("calloc"); 414 return (NULL); 415 } 416 417 /* Actually try to parse the JSON into the tokens. */ 418 419 r = jsmn_parse(&p, buf, sz, tok, tokcount); 420 if (r < 0 && JSMN_ERROR_NOMEM == r) { 421 tokcount *= 2; 422 free(tok); 423 goto again; 424 } else if (r < 0) { 425 warnx("jsmn_parse: %d", r); 426 free(tok); 427 return (NULL); 428 } 429 430 /* Now parse the tokens into a tree. */ 431 432 n = jsmntree_alloc(tok, buf, r); 433 free(tok); 434 return (n); 435 } 436 437 /* 438 * Format the "new-reg" resource request. 439 */ 440 char * 441 json_fmt_newreg(const char *license) 442 { 443 int c; 444 char *p; 445 446 c = asprintf(&p, "{" 447 "\"resource\": \"new-reg\", " 448 "\"agreement\": \"%s\"" 449 "}", 450 license); 451 if (-1 == c) { 452 warn("asprintf"); 453 p = NULL; 454 } 455 return (p); 456 } 457 458 /* 459 * Format the "new-authz" resource request. 460 */ 461 char * 462 json_fmt_newauthz(const char *domain) 463 { 464 int c; 465 char *p; 466 467 c = asprintf(&p, "{" 468 "\"resource\": \"new-authz\", " 469 "\"identifier\": " 470 "{\"type\": \"dns\", \"value\": \"%s\"}" 471 "}", 472 domain); 473 if (-1 == c) { 474 warn("asprintf"); 475 p = NULL; 476 } 477 return (p); 478 } 479 480 /* 481 * Format the "challenge" resource request. 482 */ 483 char * 484 json_fmt_challenge(const char *token, const char *thumb) 485 { 486 int c; 487 char *p; 488 489 c = asprintf(&p, "{" 490 "\"resource\": \"challenge\", " 491 "\"keyAuthorization\": \"%s.%s\"" 492 "}", 493 token, thumb); 494 if (-1 == c) { 495 warn("asprintf"); 496 p = NULL; 497 } 498 return (p); 499 } 500 501 /* 502 * Format the "new-cert" resource request. 503 */ 504 char * 505 json_fmt_revokecert(const char *cert) 506 { 507 int c; 508 char *p; 509 510 c = asprintf(&p, "{" 511 "\"resource\": \"revoke-cert\", " 512 "\"certificate\": \"%s\"" 513 "}", 514 cert); 515 if (-1 == c) { 516 warn("asprintf"); 517 p = NULL; 518 } 519 return (p); 520 } 521 522 /* 523 * Format the "new-cert" resource request. 524 */ 525 char * 526 json_fmt_newcert(const char *cert) 527 { 528 int c; 529 char *p; 530 531 c = asprintf(&p, "{" 532 "\"resource\": \"new-cert\", " 533 "\"csr\": \"%s\"" 534 "}", 535 cert); 536 if (-1 == c) { 537 warn("asprintf"); 538 p = NULL; 539 } 540 return (p); 541 } 542 543 /* 544 * Header component of json_fmt_signed(). 545 */ 546 char * 547 json_fmt_header_rsa(const char *exp, const char *mod) 548 { 549 int c; 550 char *p; 551 552 c = asprintf(&p, "{" 553 "\"alg\": \"RS256\", " 554 "\"jwk\": " 555 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}" 556 "}", 557 exp, mod); 558 if (-1 == c) { 559 warn("asprintf"); 560 p = NULL; 561 } 562 return (p); 563 } 564 565 /* 566 * Protected component of json_fmt_signed(). 567 */ 568 char * 569 json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce) 570 { 571 int c; 572 char *p; 573 574 c = asprintf(&p, "{" 575 "\"alg\": \"RS256\", " 576 "\"jwk\": " 577 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, " 578 "\"nonce\": \"%s\"" 579 "}", 580 exp, mod, nce); 581 if (-1 == c) { 582 warn("asprintf"); 583 p = NULL; 584 } 585 return (p); 586 } 587 588 /* 589 * Signed message contents for the CA server. 590 */ 591 char * 592 json_fmt_signed(const char *header, const char *protected, 593 const char *payload, const char *digest) 594 { 595 int c; 596 char *p; 597 598 c = asprintf(&p, "{" 599 "\"header\": %s, " 600 "\"protected\": \"%s\", " 601 "\"payload\": \"%s\", " 602 "\"signature\": \"%s\"" 603 "}", 604 header, protected, payload, digest); 605 if (-1 == c) { 606 warn("asprintf"); 607 p = NULL; 608 } 609 return (p); 610 } 611 612 /* 613 * Produce thumbprint input. 614 * This isn't technically a JSON string--it's the input we'll use for 615 * hashing and digesting. 616 * However, it's in the form of a JSON string, so do it here. 617 */ 618 char * 619 json_fmt_thumb_rsa(const char *exp, const char *mod) 620 { 621 int c; 622 char *p; 623 624 /*NOTE: WHITESPACE IS IMPORTANT. */ 625 626 c = asprintf(&p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", 627 exp, mod); 628 if (-1 == c) { 629 warn("asprintf"); 630 p = NULL; 631 } 632 return (p); 633 } 634