1 /* $Id: json.c,v 1.16 2020/01/22 22:25:22 tedu 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 (sz == 0) 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 (n->d.str == NULL) 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 (n->d.obj == NULL) 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 (n->d.array == NULL) 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 (p == NULL) 154 return; 155 for (i = 0; i < p->max; i++) { 156 struct jsmnn *n = &p->nodes[i]; 157 switch (n->type) { 158 case JSMN_ARRAY: 159 free(n->d.array); 160 break; 161 case JSMN_OBJECT: 162 free(n->d.obj); 163 break; 164 case JSMN_PRIMITIVE: 165 free(n->d.str); 166 break; 167 case JSMN_STRING: 168 free(n->d.str); 169 break; 170 case JSMN_UNDEFINED: 171 break; 172 } 173 } 174 free(p->nodes); 175 free(p); 176 } 177 178 /* 179 * Allocate a tree representation of "t". 180 * This returns NULL on allocation failure or when sz is zero, in which 181 * case all resources allocated along the way are freed already. 182 */ 183 static struct jsmnn * 184 jsmntree_alloc(jsmntok_t *t, const char *js, size_t sz) 185 { 186 struct jsmnn *first; 187 struct parse *p; 188 189 if (sz == 0) 190 return NULL; 191 192 p = calloc(1, sizeof(struct parse)); 193 if (p == NULL) 194 return NULL; 195 196 p->max = sz; 197 p->nodes = calloc(p->max, sizeof(struct jsmnn)); 198 if (p->nodes == NULL) { 199 free(p); 200 return NULL; 201 } 202 203 if (build(p, &first, t, js, sz) < 0) { 204 jsmnparse_free(p); 205 first = NULL; 206 } 207 208 return first; 209 } 210 211 /* 212 * Call through to free parse contents. 213 */ 214 void 215 json_free(struct jsmnn *first) 216 { 217 218 if (first != NULL) 219 jsmnparse_free(first->p); 220 } 221 222 /* 223 * Just check that the array object is in fact an object. 224 */ 225 static struct jsmnn * 226 json_getarrayobj(struct jsmnn *n) 227 { 228 229 return n->type != JSMN_OBJECT ? NULL : n; 230 } 231 232 /* 233 * Get a string element from an array 234 */ 235 static char * 236 json_getarraystr(struct jsmnn *n) 237 { 238 return n->type != JSMN_STRING ? NULL : n->d.str; 239 } 240 241 /* 242 * Extract an array from the returned JSON object, making sure that it's 243 * the correct type. 244 * Returns NULL on failure. 245 */ 246 static struct jsmnn * 247 json_getarray(struct jsmnn *n, const char *name) 248 { 249 size_t i; 250 251 if (n->type != JSMN_OBJECT) 252 return NULL; 253 for (i = 0; i < n->fields; i++) { 254 if (n->d.obj[i].lhs->type != JSMN_STRING && 255 n->d.obj[i].lhs->type != JSMN_PRIMITIVE) 256 continue; 257 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 258 continue; 259 break; 260 } 261 if (i == n->fields) 262 return NULL; 263 if (n->d.obj[i].rhs->type != JSMN_ARRAY) 264 return NULL; 265 return n->d.obj[i].rhs; 266 } 267 268 #ifdef notyet 269 /* 270 * Extract subtree from the returned JSON object, making sure that it's 271 * the correct type. 272 * Returns NULL on failure. 273 */ 274 static struct jsmnn * 275 json_getobj(struct jsmnn *n, const char *name) 276 { 277 size_t i; 278 279 if (n->type != JSMN_OBJECT) 280 return NULL; 281 for (i = 0; i < n->fields; i++) { 282 if (n->d.obj[i].lhs->type != JSMN_STRING && 283 n->d.obj[i].lhs->type != JSMN_PRIMITIVE) 284 continue; 285 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 286 continue; 287 break; 288 } 289 if (i == n->fields) 290 return NULL; 291 if (n->d.obj[i].rhs->type != JSMN_OBJECT) 292 return NULL; 293 return n->d.obj[i].rhs; 294 } 295 #endif /* notyet */ 296 297 /* 298 * Extract a single string from the returned JSON object, making sure 299 * that it's the correct type. 300 * Returns NULL on failure. 301 */ 302 static char * 303 json_getstr(struct jsmnn *n, const char *name) 304 { 305 size_t i; 306 char *cp; 307 308 if (n->type != JSMN_OBJECT) 309 return NULL; 310 for (i = 0; i < n->fields; i++) { 311 if (n->d.obj[i].lhs->type != JSMN_STRING && 312 n->d.obj[i].lhs->type != JSMN_PRIMITIVE) 313 continue; 314 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 315 continue; 316 break; 317 } 318 if (i == n->fields) 319 return NULL; 320 if (n->d.obj[i].rhs->type != JSMN_STRING && 321 n->d.obj[i].rhs->type != JSMN_PRIMITIVE) 322 return NULL; 323 324 cp = strdup(n->d.obj[i].rhs->d.str); 325 if (cp == NULL) 326 warn("strdup"); 327 return cp; 328 } 329 330 /* 331 * Completely free the challenge response body. 332 */ 333 void 334 json_free_challenge(struct chng *p) 335 { 336 337 free(p->uri); 338 free(p->token); 339 p->uri = p->token = NULL; 340 } 341 342 /* 343 * Parse the response from the ACME server when we're waiting to see 344 * whether the challenge has been ok. 345 */ 346 enum chngstatus 347 json_parse_response(struct jsmnn *n) 348 { 349 char *resp; 350 enum chngstatus rc; 351 352 if (n == NULL) 353 return CHNG_INVALID; 354 if ((resp = json_getstr(n, "status")) == NULL) 355 return CHNG_INVALID; 356 357 if (strcmp(resp, "valid") == 0) 358 rc = CHNG_VALID; 359 else if (strcmp(resp, "pending") == 0) 360 rc = CHNG_PENDING; 361 else if (strcmp(resp, "processing") == 0) 362 rc = CHNG_PROCESSING; 363 else 364 rc = CHNG_INVALID; 365 366 free(resp); 367 return rc; 368 } 369 370 /* 371 * Parse the response from a new-authz, which consists of challenge 372 * information, into a structure. 373 * We only care about the HTTP-01 response. 374 */ 375 int 376 json_parse_challenge(struct jsmnn *n, struct chng *p) 377 { 378 struct jsmnn *array, *obj; 379 size_t i; 380 int rc; 381 char *type; 382 383 if (n == NULL) 384 return 0; 385 386 array = json_getarray(n, "challenges"); 387 if (array == NULL) 388 return 0; 389 390 for (i = 0; i < array->fields; i++) { 391 obj = json_getarrayobj(array->d.array[i]); 392 if (obj == NULL) 393 continue; 394 type = json_getstr(obj, "type"); 395 if (type == NULL) 396 continue; 397 rc = strcmp(type, "http-01"); 398 free(type); 399 if (rc) 400 continue; 401 p->uri = json_getstr(obj, "url"); 402 p->token = json_getstr(obj, "token"); 403 p->status = json_parse_response(obj); 404 return p->uri != NULL && p->token != NULL; 405 } 406 407 return 0; 408 } 409 410 static enum orderstatus 411 json_parse_order_status(struct jsmnn *n) 412 { 413 char *status; 414 415 if (n == NULL) 416 return ORDER_INVALID; 417 418 if ((status = json_getstr(n, "status")) == NULL) 419 return ORDER_INVALID; 420 421 if (strcmp(status, "pending") == 0) 422 return ORDER_PENDING; 423 else if (strcmp(status, "ready") == 0) 424 return ORDER_READY; 425 else if (strcmp(status, "processing") == 0) 426 return ORDER_PROCESSING; 427 else if (strcmp(status, "valid") == 0) 428 return ORDER_VALID; 429 else if (strcmp(status, "invalid") == 0) 430 return ORDER_INVALID; 431 else 432 return ORDER_INVALID; 433 } 434 435 /* 436 * Parse the response from a newOrder, which consists of a status 437 * a list of authorization urls and a finalize url into a struct. 438 */ 439 int 440 json_parse_order(struct jsmnn *n, struct order *order) 441 { 442 struct jsmnn *array; 443 size_t i; 444 char *finalize, *str; 445 446 order->status = json_parse_order_status(n); 447 448 if (n == NULL) 449 return 0; 450 451 if ((finalize = json_getstr(n, "finalize")) == NULL) { 452 warnx("no finalize field in order response"); 453 return 0; 454 } 455 456 if ((order->finalize = strdup(finalize)) == NULL) 457 goto err; 458 459 if ((array = json_getarray(n, "authorizations")) == NULL) 460 goto err; 461 462 if (array->fields > 0) { 463 order->auths = calloc(sizeof(*order->auths), array->fields); 464 if (order->auths == NULL) { 465 warn("malloc"); 466 goto err; 467 } 468 order->authsz = array->fields; 469 } 470 471 for (i = 0; i < array->fields; i++) { 472 str = json_getarraystr(array->d.array[i]); 473 if (str == NULL) 474 continue; 475 if ((order->auths[i] = strdup(str)) == NULL) { 476 warn("strdup"); 477 goto err; 478 } 479 } 480 return 1; 481 err: 482 json_free_order(order); 483 return 0; 484 } 485 486 int 487 json_parse_upd_order(struct jsmnn *n, struct order *order) 488 { 489 char *certificate; 490 order->status = json_parse_order_status(n); 491 if ((certificate = json_getstr(n, "certificate")) != NULL) { 492 if ((order->certificate = strdup(certificate)) == NULL) 493 return 0; 494 } 495 return 1; 496 } 497 498 void 499 json_free_order(struct order *order) 500 { 501 size_t i; 502 503 free(order->finalize); 504 order->finalize = NULL; 505 for(i = 0; i < order->authsz; i++) 506 free(order->auths[i]); 507 free(order->auths); 508 509 order->finalize = NULL; 510 order->auths = NULL; 511 order->authsz = 0; 512 } 513 514 /* 515 * Extract the CA paths from the JSON response object. 516 * Return zero on failure, non-zero on success. 517 */ 518 int 519 json_parse_capaths(struct jsmnn *n, struct capaths *p) 520 { 521 if (n == NULL) 522 return 0; 523 524 p->newaccount = json_getstr(n, "newAccount"); 525 p->newnonce = json_getstr(n, "newNonce"); 526 p->neworder = json_getstr(n, "newOrder"); 527 p->revokecert = json_getstr(n, "revokeCert"); 528 529 return p->newaccount != NULL && p->newnonce != NULL && 530 p->neworder != NULL && p->revokecert != NULL; 531 } 532 533 /* 534 * Free up all of our CA-noted paths (which may all be NULL). 535 */ 536 void 537 json_free_capaths(struct capaths *p) 538 { 539 540 free(p->newaccount); 541 free(p->newnonce); 542 free(p->neworder); 543 free(p->revokecert); 544 memset(p, 0, sizeof(struct capaths)); 545 } 546 547 /* 548 * Parse an HTTP response body from a buffer of size "sz". 549 * Returns an opaque pointer on success, otherwise NULL on error. 550 */ 551 struct jsmnn * 552 json_parse(const char *buf, size_t sz) 553 { 554 struct jsmnn *n; 555 jsmn_parser p; 556 jsmntok_t *tok, *ntok; 557 int r; 558 size_t tokcount; 559 560 jsmn_init(&p); 561 tokcount = 128; 562 563 if ((tok = calloc(tokcount, sizeof(jsmntok_t))) == NULL) { 564 warn("calloc"); 565 return NULL; 566 } 567 568 /* Do this until we don't need any more tokens. */ 569 again: 570 /* Actually try to parse the JSON into the tokens. */ 571 r = jsmn_parse(&p, buf, sz, tok, tokcount); 572 if (r < 0 && r == JSMN_ERROR_NOMEM) { 573 if ((ntok = recallocarray(tok, tokcount, tokcount * 2, 574 sizeof(jsmntok_t))) == NULL) { 575 warn("calloc"); 576 free(tok); 577 return NULL; 578 } 579 tok = ntok; 580 tokcount *= 2; 581 goto again; 582 } else if (r < 0) { 583 warnx("jsmn_parse: %d", r); 584 free(tok); 585 return NULL; 586 } 587 588 /* Now parse the tokens into a tree. */ 589 590 n = jsmntree_alloc(tok, buf, r); 591 free(tok); 592 return n; 593 } 594 595 /* 596 * Format the "newAccount" resource request to check if the account exist. 597 */ 598 char * 599 json_fmt_chkacc(void) 600 { 601 int c; 602 char *p; 603 604 c = asprintf(&p, "{" 605 "\"termsOfServiceAgreed\": true, " 606 "\"onlyReturnExisting\": true" 607 "}"); 608 if (c == -1) { 609 warn("asprintf"); 610 p = NULL; 611 } 612 return p; 613 } 614 615 /* 616 * Format the "newAccount" resource request. 617 */ 618 char * 619 json_fmt_newacc(void) 620 { 621 int c; 622 char *p; 623 624 c = asprintf(&p, "{" 625 "\"termsOfServiceAgreed\": true" 626 "}"); 627 if (c == -1) { 628 warn("asprintf"); 629 p = NULL; 630 } 631 return p; 632 } 633 634 /* 635 * Format the "newOrder" resource request 636 */ 637 char * 638 json_fmt_neworder(const char *const *alts, size_t altsz) 639 { 640 size_t i; 641 int c; 642 char *p, *t; 643 644 if ((p = strdup("{ \"identifiers\": [")) == NULL) 645 goto err; 646 647 t = p; 648 for (i = 0; i < altsz; i++) { 649 c = asprintf(&p, 650 "%s { \"type\": \"dns\", \"value\": \"%s\" }%s", 651 t, alts[i], i + 1 == altsz ? "" : ","); 652 free(t); 653 if (c == -1) { 654 warn("asprintf"); 655 p = NULL; 656 goto err; 657 } 658 t = p; 659 } 660 c = asprintf(&p, "%s ] }", t); 661 free(t); 662 if (c == -1) { 663 warn("asprintf"); 664 p = NULL; 665 } 666 return p; 667 err: 668 free(p); 669 return NULL; 670 } 671 672 /* 673 * Format the revoke resource request. 674 */ 675 char * 676 json_fmt_revokecert(const char *cert) 677 { 678 int c; 679 char *p; 680 681 c = asprintf(&p, "{" 682 "\"certificate\": \"%s\"" 683 "}", 684 cert); 685 if (c == -1) { 686 warn("asprintf"); 687 p = NULL; 688 } 689 return p; 690 } 691 692 /* 693 * Format the "new-cert" resource request. 694 */ 695 char * 696 json_fmt_newcert(const char *cert) 697 { 698 int c; 699 char *p; 700 701 c = asprintf(&p, "{" 702 "\"csr\": \"%s\"" 703 "}", 704 cert); 705 if (c == -1) { 706 warn("asprintf"); 707 p = NULL; 708 } 709 return p; 710 } 711 712 /* 713 * Protected component of json_fmt_signed(). 714 */ 715 char * 716 json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce, 717 const char *url) 718 { 719 int c; 720 char *p; 721 722 c = asprintf(&p, "{" 723 "\"alg\": \"RS256\", " 724 "\"jwk\": " 725 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, " 726 "\"nonce\": \"%s\", " 727 "\"url\": \"%s\"" 728 "}", 729 exp, mod, nce, url); 730 if (c == -1) { 731 warn("asprintf"); 732 p = NULL; 733 } 734 return p; 735 } 736 737 /* 738 * Protected component of json_fmt_signed(). 739 */ 740 char * 741 json_fmt_protected_ec(const char *x, const char *y, const char *nce, 742 const char *url) 743 { 744 int c; 745 char *p; 746 747 c = asprintf(&p, "{" 748 "\"alg\": \"ES384\", " 749 "\"jwk\": " 750 "{\"crv\": \"P-384\", \"kty\": \"EC\", \"x\": \"%s\", " 751 "\"y\": \"%s\"}, \"nonce\": \"%s\", \"url\": \"%s\"" 752 "}", 753 x, y, nce, url); 754 if (c == -1) { 755 warn("asprintf"); 756 p = NULL; 757 } 758 return p; 759 } 760 761 /* 762 * Protected component of json_fmt_signed(). 763 */ 764 char * 765 json_fmt_protected_kid(const char *alg, const char *kid, const char *nce, 766 const char *url) 767 { 768 int c; 769 char *p; 770 771 c = asprintf(&p, "{" 772 "\"alg\": \"%s\", " 773 "\"kid\": \"%s\", " 774 "\"nonce\": \"%s\", " 775 "\"url\": \"%s\"" 776 "}", 777 alg, kid, nce, url); 778 if (c == -1) { 779 warn("asprintf"); 780 p = NULL; 781 } 782 return p; 783 } 784 785 /* 786 * Signed message contents for the CA server. 787 */ 788 char * 789 json_fmt_signed(const char *protected, const char *payload, const char *digest) 790 { 791 int c; 792 char *p; 793 794 c = asprintf(&p, "{" 795 "\"protected\": \"%s\", " 796 "\"payload\": \"%s\", " 797 "\"signature\": \"%s\"" 798 "}", 799 protected, payload, digest); 800 if (c == -1) { 801 warn("asprintf"); 802 p = NULL; 803 } 804 return p; 805 } 806 807 /* 808 * Produce thumbprint input. 809 * This isn't technically a JSON string--it's the input we'll use for 810 * hashing and digesting. 811 * However, it's in the form of a JSON string, so do it here. 812 */ 813 char * 814 json_fmt_thumb_rsa(const char *exp, const char *mod) 815 { 816 int c; 817 char *p; 818 819 /*NOTE: WHITESPACE IS IMPORTANT. */ 820 821 c = asprintf(&p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", 822 exp, mod); 823 if (c == -1) { 824 warn("asprintf"); 825 p = NULL; 826 } 827 return p; 828 } 829 830 /* 831 * Produce thumbprint input. 832 * This isn't technically a JSON string--it's the input we'll use for 833 * hashing and digesting. 834 * However, it's in the form of a JSON string, so do it here. 835 */ 836 char * 837 json_fmt_thumb_ec(const char *x, const char *y) 838 { 839 int c; 840 char *p; 841 842 /*NOTE: WHITESPACE IS IMPORTANT. */ 843 844 c = asprintf(&p, "{\"crv\":\"P-384\",\"kty\":\"EC\",\"x\":\"%s\"," 845 "\"y\":\"%s\"}", 846 x, y); 847 if (c == -1) { 848 warn("asprintf"); 849 p = NULL; 850 } 851 return p; 852 } 853