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