1 /* $Id: json.c,v 1.14 2019/06/18 18:50:07 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 #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 ((order->authsz = array->fields) > 0) { 463 order->auths = calloc(sizeof(*order->auths), order->authsz); 464 if (order->auths == NULL) { 465 warn("malloc"); 466 goto err; 467 } 468 } 469 470 for (i = 0; i < array->fields; i++) { 471 str = json_getarraystr(array->d.array[i]); 472 if (str == NULL) 473 continue; 474 if ((order->auths[i] = strdup(str)) == NULL) { 475 warn("strdup"); 476 goto err; 477 } 478 } 479 return 1; 480 err: 481 json_free_order(order); 482 return 0; 483 } 484 485 int 486 json_parse_upd_order(struct jsmnn *n, struct order *order) 487 { 488 char *certificate; 489 order->status = json_parse_order_status(n); 490 if ((certificate = json_getstr(n, "certificate")) != NULL) { 491 if ((order->certificate = strdup(certificate)) == NULL) 492 return 0; 493 } 494 return 1; 495 } 496 497 void 498 json_free_order(struct order *order) 499 { 500 size_t i; 501 502 free(order->finalize); 503 order->finalize = NULL; 504 for(i = 0; i < order->authsz; i++) 505 free(order->auths[i]); 506 free(order->auths); 507 508 order->finalize = NULL; 509 order->auths = NULL; 510 order->authsz = 0; 511 } 512 513 /* 514 * Extract the CA paths from the JSON response object. 515 * Return zero on failure, non-zero on success. 516 */ 517 int 518 json_parse_capaths(struct jsmnn *n, struct capaths *p) 519 { 520 if (n == NULL) 521 return 0; 522 523 p->newaccount = json_getstr(n, "newAccount"); 524 p->newnonce = json_getstr(n, "newNonce"); 525 p->neworder = json_getstr(n, "newOrder"); 526 p->revokecert = json_getstr(n, "revokeCert"); 527 528 return p->newaccount != NULL && p->newnonce != NULL && 529 p->neworder != NULL && p->revokecert != NULL; 530 } 531 532 /* 533 * Free up all of our CA-noted paths (which may all be NULL). 534 */ 535 void 536 json_free_capaths(struct capaths *p) 537 { 538 539 free(p->newaccount); 540 free(p->newnonce); 541 free(p->neworder); 542 free(p->revokecert); 543 memset(p, 0, sizeof(struct capaths)); 544 } 545 546 /* 547 * Parse an HTTP response body from a buffer of size "sz". 548 * Returns an opaque pointer on success, otherwise NULL on error. 549 */ 550 struct jsmnn * 551 json_parse(const char *buf, size_t sz) 552 { 553 struct jsmnn *n; 554 jsmn_parser p; 555 jsmntok_t *tok, *ntok; 556 int r; 557 size_t tokcount; 558 559 jsmn_init(&p); 560 tokcount = 128; 561 562 if ((tok = calloc(tokcount, sizeof(jsmntok_t))) == NULL) { 563 warn("calloc"); 564 return NULL; 565 } 566 567 /* Do this until we don't need any more tokens. */ 568 again: 569 /* Actually try to parse the JSON into the tokens. */ 570 r = jsmn_parse(&p, buf, sz, tok, tokcount); 571 if (r < 0 && r == JSMN_ERROR_NOMEM) { 572 if ((ntok = recallocarray(tok, tokcount, tokcount * 2, 573 sizeof(jsmntok_t))) == NULL) { 574 warn("calloc"); 575 free(tok); 576 return NULL; 577 } 578 tok = ntok; 579 tokcount *= 2; 580 goto again; 581 } else if (r < 0) { 582 warnx("jsmn_parse: %d", r); 583 free(tok); 584 return NULL; 585 } 586 587 /* Now parse the tokens into a tree. */ 588 589 n = jsmntree_alloc(tok, buf, r); 590 free(tok); 591 return n; 592 } 593 594 /* 595 * Format the "newAccount" resource request to check if the account exist. 596 */ 597 char * 598 json_fmt_chkacc(void) 599 { 600 int c; 601 char *p; 602 603 c = asprintf(&p, "{" 604 "\"termsOfServiceAgreed\": true, " 605 "\"onlyReturnExisting\": true" 606 "}"); 607 if (c == -1) { 608 warn("asprintf"); 609 p = NULL; 610 } 611 return p; 612 } 613 614 /* 615 * Format the "newAccount" resource request. 616 */ 617 char * 618 json_fmt_newacc(void) 619 { 620 int c; 621 char *p; 622 623 c = asprintf(&p, "{" 624 "\"termsOfServiceAgreed\": true" 625 "}"); 626 if (c == -1) { 627 warn("asprintf"); 628 p = NULL; 629 } 630 return p; 631 } 632 633 /* 634 * Format the "newOrder" resource request 635 */ 636 char * 637 json_fmt_neworder(const char *const *alts, size_t altsz) 638 { 639 size_t i; 640 int c; 641 char *p, *t; 642 643 if ((p = strdup("{ \"identifiers\": [")) == NULL) 644 goto err; 645 646 t = p; 647 for (i = 0; i < altsz; i++) { 648 c = asprintf(&p, 649 "%s { \"type\": \"dns\", \"value\": \"%s\" }%s", 650 t, alts[i], i + 1 == altsz ? "" : ","); 651 free(t); 652 if (c == -1) { 653 warn("asprintf"); 654 p = NULL; 655 goto err; 656 } 657 t = p; 658 } 659 c = asprintf(&p, "%s ] }", t); 660 free(t); 661 if (c == -1) { 662 warn("asprintf"); 663 p = NULL; 664 } 665 return p; 666 err: 667 free(p); 668 return NULL; 669 } 670 671 /* 672 * Format the revoke resource request. 673 */ 674 char * 675 json_fmt_revokecert(const char *cert) 676 { 677 int c; 678 char *p; 679 680 c = asprintf(&p, "{" 681 "\"certificate\": \"%s\"" 682 "}", 683 cert); 684 if (c == -1) { 685 warn("asprintf"); 686 p = NULL; 687 } 688 return p; 689 } 690 691 /* 692 * Format the "new-cert" resource request. 693 */ 694 char * 695 json_fmt_newcert(const char *cert) 696 { 697 int c; 698 char *p; 699 700 c = asprintf(&p, "{" 701 "\"csr\": \"%s\"" 702 "}", 703 cert); 704 if (c == -1) { 705 warn("asprintf"); 706 p = NULL; 707 } 708 return p; 709 } 710 711 /* 712 * Protected component of json_fmt_signed(). 713 */ 714 char * 715 json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce, 716 const char *url) 717 { 718 int c; 719 char *p; 720 721 c = asprintf(&p, "{" 722 "\"alg\": \"RS256\", " 723 "\"jwk\": " 724 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, " 725 "\"nonce\": \"%s\", " 726 "\"url\": \"%s\"" 727 "}", 728 exp, mod, nce, url); 729 if (c == -1) { 730 warn("asprintf"); 731 p = NULL; 732 } 733 return p; 734 } 735 736 /* 737 * Protected component of json_fmt_signed(). 738 */ 739 char * 740 json_fmt_protected_ec(const char *x, const char *y, const char *nce, 741 const char *url) 742 { 743 int c; 744 char *p; 745 746 c = asprintf(&p, "{" 747 "\"alg\": \"ES384\", " 748 "\"jwk\": " 749 "{\"crv\": \"P-384\", \"kty\": \"EC\", \"x\": \"%s\", " 750 "\"y\": \"%s\"}, \"nonce\": \"%s\", \"url\": \"%s\"" 751 "}", 752 x, y, nce, url); 753 if (c == -1) { 754 warn("asprintf"); 755 p = NULL; 756 } 757 return p; 758 } 759 760 /* 761 * Protected component of json_fmt_signed(). 762 */ 763 char * 764 json_fmt_protected_kid(const char *alg, const char *kid, const char *nce, 765 const char *url) 766 { 767 int c; 768 char *p; 769 770 c = asprintf(&p, "{" 771 "\"alg\": \"%s\", " 772 "\"kid\": \"%s\", " 773 "\"nonce\": \"%s\", " 774 "\"url\": \"%s\"" 775 "}", 776 alg, kid, nce, url); 777 if (c == -1) { 778 warn("asprintf"); 779 p = NULL; 780 } 781 return p; 782 } 783 784 /* 785 * Signed message contents for the CA server. 786 */ 787 char * 788 json_fmt_signed(const char *protected, const char *payload, const char *digest) 789 { 790 int c; 791 char *p; 792 793 c = asprintf(&p, "{" 794 "\"protected\": \"%s\", " 795 "\"payload\": \"%s\", " 796 "\"signature\": \"%s\"" 797 "}", 798 protected, payload, digest); 799 if (c == -1) { 800 warn("asprintf"); 801 p = NULL; 802 } 803 return p; 804 } 805 806 /* 807 * Produce thumbprint input. 808 * This isn't technically a JSON string--it's the input we'll use for 809 * hashing and digesting. 810 * However, it's in the form of a JSON string, so do it here. 811 */ 812 char * 813 json_fmt_thumb_rsa(const char *exp, const char *mod) 814 { 815 int c; 816 char *p; 817 818 /*NOTE: WHITESPACE IS IMPORTANT. */ 819 820 c = asprintf(&p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", 821 exp, mod); 822 if (c == -1) { 823 warn("asprintf"); 824 p = NULL; 825 } 826 return p; 827 } 828 829 /* 830 * Produce thumbprint input. 831 * This isn't technically a JSON string--it's the input we'll use for 832 * hashing and digesting. 833 * However, it's in the form of a JSON string, so do it here. 834 */ 835 char * 836 json_fmt_thumb_ec(const char *x, const char *y) 837 { 838 int c; 839 char *p; 840 841 /*NOTE: WHITESPACE IS IMPORTANT. */ 842 843 c = asprintf(&p, "{\"crv\":\"P-384\",\"kty\":\"EC\",\"x\":\"%s\"," 844 "\"y\":\"%s\"}", 845 x, y); 846 if (c == -1) { 847 warn("asprintf"); 848 p = NULL; 849 } 850 return p; 851 } 852