1 /* $Id: json.c,v 1.10 2017/11/27 01:58:52 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 * Extract an array from the returned JSON object, making sure that it's 234 * the correct type. 235 * Returns NULL on failure. 236 */ 237 static struct jsmnn * 238 json_getarray(struct jsmnn *n, const char *name) 239 { 240 size_t i; 241 242 if (n->type != JSMN_OBJECT) 243 return NULL; 244 for (i = 0; i < n->fields; i++) { 245 if (n->d.obj[i].lhs->type != JSMN_STRING && 246 n->d.obj[i].lhs->type != JSMN_PRIMITIVE) 247 continue; 248 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 249 continue; 250 break; 251 } 252 if (i == n->fields) 253 return NULL; 254 if (n->d.obj[i].rhs->type != JSMN_ARRAY) 255 return NULL; 256 return n->d.obj[i].rhs; 257 } 258 259 /* 260 * Extract subtree from the returned JSON object, making sure that it's 261 * the correct type. 262 * Returns NULL on failure. 263 */ 264 static struct jsmnn * 265 json_getobj(struct jsmnn *n, const char *name) 266 { 267 size_t i; 268 269 if (n->type != JSMN_OBJECT) 270 return NULL; 271 for (i = 0; i < n->fields; i++) { 272 if (n->d.obj[i].lhs->type != JSMN_STRING && 273 n->d.obj[i].lhs->type != JSMN_PRIMITIVE) 274 continue; 275 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 276 continue; 277 break; 278 } 279 if (i == n->fields) 280 return NULL; 281 if (n->d.obj[i].rhs->type != JSMN_OBJECT) 282 return NULL; 283 return n->d.obj[i].rhs; 284 } 285 286 /* 287 * Extract a single string from the returned JSON object, making sure 288 * that it's the correct type. 289 * Returns NULL on failure. 290 */ 291 static char * 292 json_getstr(struct jsmnn *n, const char *name) 293 { 294 size_t i; 295 char *cp; 296 297 if (n->type != JSMN_OBJECT) 298 return NULL; 299 for (i = 0; i < n->fields; i++) { 300 if (n->d.obj[i].lhs->type != JSMN_STRING && 301 n->d.obj[i].lhs->type != JSMN_PRIMITIVE) 302 continue; 303 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 304 continue; 305 break; 306 } 307 if (i == n->fields) 308 return NULL; 309 if (n->d.obj[i].rhs->type != JSMN_STRING && 310 n->d.obj[i].rhs->type != JSMN_PRIMITIVE) 311 return NULL; 312 313 cp = strdup(n->d.obj[i].rhs->d.str); 314 if (cp == NULL) 315 warn("strdup"); 316 return cp; 317 } 318 319 /* 320 * Completely free the challenge response body. 321 */ 322 void 323 json_free_challenge(struct chng *p) 324 { 325 326 free(p->uri); 327 free(p->token); 328 p->uri = p->token = NULL; 329 } 330 331 /* 332 * Parse the response from the ACME server when we're waiting to see 333 * whether the challenge has been ok. 334 */ 335 int 336 json_parse_response(struct jsmnn *n) 337 { 338 char *resp; 339 int rc; 340 341 if (n == NULL) 342 return -1; 343 if ((resp = json_getstr(n, "status")) == NULL) 344 return -1; 345 346 if (strcmp(resp, "valid") == 0) 347 rc = 1; 348 else if (strcmp(resp, "pending") == 0) 349 rc = 0; 350 else 351 rc = -1; 352 353 free(resp); 354 return rc; 355 } 356 357 /* 358 * Parse the response from a new-authz, which consists of challenge 359 * information, into a structure. 360 * We only care about the HTTP-01 response. 361 */ 362 int 363 json_parse_challenge(struct jsmnn *n, struct chng *p) 364 { 365 struct jsmnn *array, *obj; 366 size_t i; 367 int rc; 368 char *type; 369 370 if (n == NULL) 371 return 0; 372 373 array = json_getarray(n, "challenges"); 374 if (array == NULL) 375 return 0; 376 377 for (i = 0; i < array->fields; i++) { 378 obj = json_getarrayobj(array->d.array[i]); 379 if (obj == NULL) 380 continue; 381 type = json_getstr(obj, "type"); 382 if (type == NULL) 383 continue; 384 rc = strcmp(type, "http-01"); 385 free(type); 386 if (rc) 387 continue; 388 p->uri = json_getstr(obj, "uri"); 389 p->token = json_getstr(obj, "token"); 390 return p->uri != NULL && p->token != NULL; 391 } 392 393 return 0; 394 } 395 396 /* 397 * Extract the CA paths from the JSON response object. 398 * Return zero on failure, non-zero on success. 399 */ 400 int 401 json_parse_capaths(struct jsmnn *n, struct capaths *p) 402 { 403 struct jsmnn *meta; 404 405 if (n == NULL) 406 return 0; 407 408 meta = json_getobj(n, "meta"); 409 410 if (meta == NULL) 411 return 0; 412 413 p->newauthz = json_getstr(n, "new-authz"); 414 p->newcert = json_getstr(n, "new-cert"); 415 p->newreg = json_getstr(n, "new-reg"); 416 p->revokecert = json_getstr(n, "revoke-cert"); 417 p->agreement = json_getstr(meta, "terms-of-service"); 418 419 return p->newauthz != NULL && p->newcert != NULL && 420 p->newreg != NULL && p->revokecert != NULL && p->agreement != NULL; 421 } 422 423 /* 424 * Free up all of our CA-noted paths (which may all be NULL). 425 */ 426 void 427 json_free_capaths(struct capaths *p) 428 { 429 430 free(p->newauthz); 431 free(p->newcert); 432 free(p->newreg); 433 free(p->revokecert); 434 free(p->agreement); 435 memset(p, 0, sizeof(struct capaths)); 436 } 437 438 /* 439 * Parse an HTTP response body from a buffer of size "sz". 440 * Returns an opaque pointer on success, otherwise NULL on error. 441 */ 442 struct jsmnn * 443 json_parse(const char *buf, size_t sz) 444 { 445 struct jsmnn *n; 446 jsmn_parser p; 447 jsmntok_t *tok; 448 int r; 449 size_t tokcount; 450 451 jsmn_init(&p); 452 tokcount = 128; 453 454 /* Do this until we don't need any more tokens. */ 455 again: 456 tok = calloc(tokcount, sizeof(jsmntok_t)); 457 if (tok == NULL) { 458 warn("calloc"); 459 return NULL; 460 } 461 462 /* Actually try to parse the JSON into the tokens. */ 463 464 r = jsmn_parse(&p, buf, sz, tok, tokcount); 465 if (r < 0 && r == JSMN_ERROR_NOMEM) { 466 tokcount *= 2; 467 free(tok); 468 goto again; 469 } else if (r < 0) { 470 warnx("jsmn_parse: %d", r); 471 free(tok); 472 return NULL; 473 } 474 475 /* Now parse the tokens into a tree. */ 476 477 n = jsmntree_alloc(tok, buf, r); 478 free(tok); 479 return n; 480 } 481 482 /* 483 * Format the "new-reg" resource request. 484 */ 485 char * 486 json_fmt_newreg(const char *license) 487 { 488 int c; 489 char *p; 490 491 c = asprintf(&p, "{" 492 "\"resource\": \"new-reg\", " 493 "\"agreement\": \"%s\"" 494 "}", 495 license); 496 if (c == -1) { 497 warn("asprintf"); 498 p = NULL; 499 } 500 return p; 501 } 502 503 /* 504 * Format the "new-authz" resource request. 505 */ 506 char * 507 json_fmt_newauthz(const char *domain) 508 { 509 int c; 510 char *p; 511 512 c = asprintf(&p, "{" 513 "\"resource\": \"new-authz\", " 514 "\"identifier\": " 515 "{\"type\": \"dns\", \"value\": \"%s\"}" 516 "}", 517 domain); 518 if (c == -1) { 519 warn("asprintf"); 520 p = NULL; 521 } 522 return p; 523 } 524 525 /* 526 * Format the "challenge" resource request. 527 */ 528 char * 529 json_fmt_challenge(const char *token, const char *thumb) 530 { 531 int c; 532 char *p; 533 534 c = asprintf(&p, "{" 535 "\"resource\": \"challenge\", " 536 "\"keyAuthorization\": \"%s.%s\"" 537 "}", 538 token, thumb); 539 if (c == -1) { 540 warn("asprintf"); 541 p = NULL; 542 } 543 return p; 544 } 545 546 /* 547 * Format the "new-cert" resource request. 548 */ 549 char * 550 json_fmt_revokecert(const char *cert) 551 { 552 int c; 553 char *p; 554 555 c = asprintf(&p, "{" 556 "\"resource\": \"revoke-cert\", " 557 "\"certificate\": \"%s\"" 558 "}", 559 cert); 560 if (c == -1) { 561 warn("asprintf"); 562 p = NULL; 563 } 564 return p; 565 } 566 567 /* 568 * Format the "new-cert" resource request. 569 */ 570 char * 571 json_fmt_newcert(const char *cert) 572 { 573 int c; 574 char *p; 575 576 c = asprintf(&p, "{" 577 "\"resource\": \"new-cert\", " 578 "\"csr\": \"%s\"" 579 "}", 580 cert); 581 if (c == -1) { 582 warn("asprintf"); 583 p = NULL; 584 } 585 return p; 586 } 587 588 /* 589 * Header component of json_fmt_signed(). 590 */ 591 char * 592 json_fmt_header_rsa(const char *exp, const char *mod) 593 { 594 int c; 595 char *p; 596 597 c = asprintf(&p, "{" 598 "\"alg\": \"RS256\", " 599 "\"jwk\": " 600 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}" 601 "}", 602 exp, mod); 603 if (c == -1) { 604 warn("asprintf"); 605 p = NULL; 606 } 607 return p; 608 } 609 610 /* 611 * Protected component of json_fmt_signed(). 612 */ 613 char * 614 json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce) 615 { 616 int c; 617 char *p; 618 619 c = asprintf(&p, "{" 620 "\"alg\": \"RS256\", " 621 "\"jwk\": " 622 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, " 623 "\"nonce\": \"%s\"" 624 "}", 625 exp, mod, nce); 626 if (c == -1) { 627 warn("asprintf"); 628 p = NULL; 629 } 630 return p; 631 } 632 633 /* 634 * Signed message contents for the CA server. 635 */ 636 char * 637 json_fmt_signed(const char *header, const char *protected, 638 const char *payload, const char *digest) 639 { 640 int c; 641 char *p; 642 643 c = asprintf(&p, "{" 644 "\"header\": %s, " 645 "\"protected\": \"%s\", " 646 "\"payload\": \"%s\", " 647 "\"signature\": \"%s\"" 648 "}", 649 header, protected, payload, digest); 650 if (c == -1) { 651 warn("asprintf"); 652 p = NULL; 653 } 654 return p; 655 } 656 657 /* 658 * Produce thumbprint input. 659 * This isn't technically a JSON string--it's the input we'll use for 660 * hashing and digesting. 661 * However, it's in the form of a JSON string, so do it here. 662 */ 663 char * 664 json_fmt_thumb_rsa(const char *exp, const char *mod) 665 { 666 int c; 667 char *p; 668 669 /*NOTE: WHITESPACE IS IMPORTANT. */ 670 671 c = asprintf(&p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", 672 exp, mod); 673 if (c == -1) { 674 warn("asprintf"); 675 p = NULL; 676 } 677 return p; 678 } 679