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