1 /* $Id: json.c,v 1.4 2016/09/13 16:04:51 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 (0 == sz) 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 (NULL == n->d.str) 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 (NULL == n->d.obj) 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 (NULL == n->d.array) 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 (NULL == p) 154 return; 155 for (i = 0; i < p->max; i++) 156 if (JSMN_ARRAY == p->nodes[i].type) 157 free(p->nodes[i].d.array); 158 else if (JSMN_OBJECT == p->nodes[i].type) 159 free(p->nodes[i].d.obj); 160 else if (JSMN_PRIMITIVE == p->nodes[i].type) 161 free(p->nodes[i].d.str); 162 else if (JSMN_STRING == p->nodes[i].type) 163 free(p->nodes[i].d.str); 164 free(p->nodes); 165 free(p); 166 } 167 168 /* 169 * Allocate a tree representation of "t". 170 * This returns NULL on allocation failure or when sz is zero, in which 171 * case all resources allocated along the way are freed already. 172 */ 173 static struct jsmnn * 174 jsmntree_alloc(jsmntok_t *t, const char *js, size_t sz) 175 { 176 struct jsmnn *first; 177 struct parse *p; 178 179 if (0 == sz) 180 return (NULL); 181 182 p = calloc(1, sizeof(struct parse)); 183 if (NULL == p) 184 return (NULL); 185 186 p->max = sz; 187 p->nodes = calloc(p->max, sizeof(struct jsmnn)); 188 if (NULL == p->nodes) { 189 free(p); 190 return (NULL); 191 } 192 193 if (build(p, &first, t, js, sz) < 0) { 194 jsmnparse_free(p); 195 first = NULL; 196 } 197 198 return (first); 199 } 200 201 /* 202 * Call through to free parse contents. 203 */ 204 void 205 json_free(struct jsmnn *first) 206 { 207 208 if (NULL != first) 209 jsmnparse_free(first->p); 210 } 211 212 /* 213 * Just check that the array object is in fact an object. 214 */ 215 static struct jsmnn * 216 json_getarrayobj(struct jsmnn *n) 217 { 218 219 return (JSMN_OBJECT != n->type ? NULL : n); 220 } 221 222 /* 223 * Extract an array from the returned JSON object, making sure that it's 224 * the correct type. 225 * Returns NULL on failure. 226 */ 227 static struct jsmnn * 228 json_getarray(struct jsmnn *n, const char *name) 229 { 230 size_t i; 231 232 if (JSMN_OBJECT != n->type) 233 return (NULL); 234 for (i = 0; i < n->fields; i++) { 235 if (JSMN_STRING != n->d.obj[i].lhs->type && 236 JSMN_PRIMITIVE != n->d.obj[i].lhs->type) 237 continue; 238 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 239 continue; 240 break; 241 } 242 if (i == n->fields) 243 return (NULL); 244 if (JSMN_ARRAY != n->d.obj[i].rhs->type) 245 return (NULL); 246 return (n->d.obj[i].rhs); 247 } 248 249 /* 250 * Extract a single string from the returned JSON object, making sure 251 * that it's the correct type. 252 * Returns NULL on failure. 253 */ 254 static char * 255 json_getstr(struct jsmnn *n, const char *name) 256 { 257 size_t i; 258 char *cp; 259 260 if (JSMN_OBJECT != n->type) 261 return (NULL); 262 for (i = 0; i < n->fields; i++) { 263 if (JSMN_STRING != n->d.obj[i].lhs->type && 264 JSMN_PRIMITIVE != n->d.obj[i].lhs->type) 265 continue; 266 else if (strcmp(name, n->d.obj[i].lhs->d.str)) 267 continue; 268 break; 269 } 270 if (i == n->fields) 271 return (NULL); 272 if (JSMN_STRING != n->d.obj[i].rhs->type && 273 JSMN_PRIMITIVE != n->d.obj[i].rhs->type) 274 return (NULL); 275 276 cp = strdup(n->d.obj[i].rhs->d.str); 277 if (NULL == cp) 278 warn("strdup"); 279 return (cp); 280 } 281 282 /* 283 * Completely free the challenge response body. 284 */ 285 void 286 json_free_challenge(struct chng *p) 287 { 288 289 free(p->uri); 290 free(p->token); 291 p->uri = p->token = NULL; 292 } 293 294 /* 295 * Parse the response from the ACME server when we're waiting to see 296 * whether the challenge has been ok. 297 */ 298 int 299 json_parse_response(struct jsmnn *n) 300 { 301 char *resp; 302 int rc; 303 304 if (NULL == n) 305 return (-1); 306 if (NULL == (resp = json_getstr(n, "status"))) 307 return (-1); 308 309 if (0 == strcmp(resp, "valid")) 310 rc = 1; 311 else if (0 == strcmp(resp, "pending")) 312 rc = 0; 313 else 314 rc = -1; 315 316 free(resp); 317 return (rc); 318 } 319 320 /* 321 * Parse the response from a new-authz, which consists of challenge 322 * information, into a structure. 323 * We only care about the HTTP-01 response. 324 */ 325 int 326 json_parse_challenge(struct jsmnn *n, struct chng *p) 327 { 328 struct jsmnn *array, *obj; 329 size_t i; 330 int rc; 331 char *type; 332 333 if (NULL == n) 334 return (0); 335 336 array = json_getarray(n, "challenges"); 337 if (NULL == array) 338 return (0); 339 340 for (i = 0; i < array->fields; i++) { 341 obj = json_getarrayobj(array->d.array[i]); 342 if (NULL == obj) 343 continue; 344 type = json_getstr(obj, "type"); 345 if (NULL == type) 346 continue; 347 rc = strcmp(type, "http-01"); 348 free(type); 349 if (rc) 350 continue; 351 p->uri = json_getstr(obj, "uri"); 352 p->token = json_getstr(obj, "token"); 353 return (NULL != p->uri && 354 NULL != p->token); 355 } 356 357 return (0); 358 } 359 360 /* 361 * Extract the CA paths from the JSON response object. 362 * Return zero on failure, non-zero on success. 363 */ 364 int 365 json_parse_capaths(struct jsmnn *n, struct capaths *p) 366 { 367 368 if (NULL == n) 369 return (0); 370 371 p->newauthz = json_getstr(n, "new-authz"); 372 p->newcert = json_getstr(n, "new-cert"); 373 p->newreg = json_getstr(n, "new-reg"); 374 p->revokecert = json_getstr(n, "revoke-cert"); 375 376 return (NULL != p->newauthz && 377 NULL != p->newcert && 378 NULL != p->newreg && 379 NULL != p->revokecert); 380 } 381 382 /* 383 * Free up all of our CA-noted paths (which may all be NULL). 384 */ 385 void 386 json_free_capaths(struct capaths *p) 387 { 388 389 free(p->newauthz); 390 free(p->newcert); 391 free(p->newreg); 392 free(p->revokecert); 393 memset(p, 0, sizeof(struct capaths)); 394 } 395 396 /* 397 * Parse an HTTP response body from a buffer of size "sz". 398 * Returns an opaque pointer on success, otherwise NULL on error. 399 */ 400 struct jsmnn * 401 json_parse(const char *buf, size_t sz) 402 { 403 struct jsmnn *n; 404 jsmn_parser p; 405 jsmntok_t *tok; 406 int r; 407 size_t tokcount; 408 409 jsmn_init(&p); 410 tokcount = 128; 411 412 /* Do this until we don't need any more tokens. */ 413 again: 414 tok = calloc(tokcount, sizeof(jsmntok_t)); 415 if (NULL == tok) { 416 warn("calloc"); 417 return (NULL); 418 } 419 420 /* Actually try to parse the JSON into the tokens. */ 421 422 r = jsmn_parse(&p, buf, sz, tok, tokcount); 423 if (r < 0 && JSMN_ERROR_NOMEM == r) { 424 tokcount *= 2; 425 free(tok); 426 goto again; 427 } else if (r < 0) { 428 warnx("jsmn_parse: %d", r); 429 free(tok); 430 return (NULL); 431 } 432 433 /* Now parse the tokens into a tree. */ 434 435 n = jsmntree_alloc(tok, buf, r); 436 free(tok); 437 return (n); 438 } 439 440 /* 441 * Format the "new-reg" resource request. 442 */ 443 char * 444 json_fmt_newreg(const char *license) 445 { 446 int c; 447 char *p; 448 449 c = asprintf(&p, "{" 450 "\"resource\": \"new-reg\", " 451 "\"agreement\": \"%s\"" 452 "}", license); 453 if (-1 == c) { 454 warn("asprintf"); 455 p = NULL; 456 } 457 return (p); 458 } 459 460 /* 461 * Format the "new-authz" resource request. 462 */ 463 char * 464 json_fmt_newauthz(const char *domain) 465 { 466 int c; 467 char *p; 468 469 c = asprintf(&p, "{" 470 "\"resource\": \"new-authz\", " 471 "\"identifier\": " 472 "{\"type\": \"dns\", \"value\": \"%s\"}" 473 "}", domain); 474 if (-1 == c) { 475 warn("asprintf"); 476 p = NULL; 477 } 478 return (p); 479 } 480 481 /* 482 * Format the "challenge" resource request. 483 */ 484 char * 485 json_fmt_challenge(const char *token, const char *thumb) 486 { 487 int c; 488 char *p; 489 490 c = asprintf(&p, "{" 491 "\"resource\": \"challenge\", " 492 "\"keyAuthorization\": \"%s.%s\"" 493 "}", token, thumb); 494 if (-1 == c) { 495 warn("asprintf"); 496 p = NULL; 497 } 498 return (p); 499 } 500 501 /* 502 * Format the "new-cert" resource request. 503 */ 504 char * 505 json_fmt_revokecert(const char *cert) 506 { 507 int c; 508 char *p; 509 510 c = asprintf(&p, "{" 511 "\"resource\": \"revoke-cert\", " 512 "\"certificate\": \"%s\"" 513 "}", cert); 514 if (-1 == c) { 515 warn("asprintf"); 516 p = NULL; 517 } 518 return (p); 519 } 520 521 /* 522 * Format the "new-cert" resource request. 523 */ 524 char * 525 json_fmt_newcert(const char *cert) 526 { 527 int c; 528 char *p; 529 530 c = asprintf(&p, "{" 531 "\"resource\": \"new-cert\", " 532 "\"csr\": \"%s\"" 533 "}", cert); 534 if (-1 == c) { 535 warn("asprintf"); 536 p = NULL; 537 } 538 return (p); 539 } 540 541 /* 542 * Header component of json_fmt_signed(). 543 */ 544 char * 545 json_fmt_header_rsa(const char *exp, const char *mod) 546 { 547 int c; 548 char *p; 549 550 c = asprintf(&p, "{" 551 "\"alg\": \"RS256\", " 552 "\"jwk\": " 553 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}" 554 "}", exp, mod); 555 if (-1 == c) { 556 warn("asprintf"); 557 p = NULL; 558 } 559 return (p); 560 } 561 562 /* 563 * Protected component of json_fmt_signed(). 564 */ 565 char * 566 json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce) 567 { 568 int c; 569 char *p; 570 571 c = asprintf(&p, "{" 572 "\"alg\": \"RS256\", " 573 "\"jwk\": " 574 "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, " 575 "\"nonce\": \"%s\"" 576 "}", exp, mod, nce); 577 if (-1 == c) { 578 warn("asprintf"); 579 p = NULL; 580 } 581 return (p); 582 } 583 584 /* 585 * Signed message contents for the CA server. 586 */ 587 char * 588 json_fmt_signed(const char *header, const char *protected, 589 const char *payload, const char *digest) 590 { 591 int c; 592 char *p; 593 594 c = asprintf(&p, "{" 595 "\"header\": %s, " 596 "\"protected\": \"%s\", " 597 "\"payload\": \"%s\", " 598 "\"signature\": \"%s\"" 599 "}", header, protected, payload, digest); 600 if (-1 == c) { 601 warn("asprintf"); 602 p = NULL; 603 } 604 return (p); 605 } 606 607 /* 608 * Produce thumbprint input. 609 * This isn't technically a JSON string--it's the input we'll use for 610 * hashing and digesting. 611 * However, it's in the form of a JSON string, so do it here. 612 */ 613 char * 614 json_fmt_thumb_rsa(const char *exp, const char *mod) 615 { 616 int c; 617 char *p; 618 619 /*NOTE: WHITESPACE IS IMPORTANT. */ 620 621 c = asprintf(&p, 622 "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", 623 exp, mod); 624 if (-1 == c) { 625 warn("asprintf"); 626 p = NULL; 627 } 628 return (p); 629 } 630