xref: /openbsd/usr.sbin/acme-client/json.c (revision 6736ff2b)
1 /*	$Id: json.c,v 1.21 2020/09/14 16:00:17 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
build(struct parse * parse,struct jsmnn ** np,jsmntok_t * t,const char * js,size_t sz)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
jsmnparse_free(struct parse * p)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 *
jsmntree_alloc(jsmntok_t * t,const char * js,size_t sz)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
json_free(struct jsmnn * first)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 *
json_getarrayobj(struct jsmnn * n)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 *
json_getarraystr(struct jsmnn * n)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 *
json_getarray(struct jsmnn * n,const char * name)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 *
json_getobj(struct jsmnn * n,const char * name)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 *
json_getstr(struct jsmnn * n,const char * name)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
json_free_challenge(struct chng * p)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
json_parse_response(struct jsmnn * n)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
json_parse_challenge(struct jsmnn * n,struct chng * p)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
json_parse_order_status(struct jsmnn * n)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
json_parse_order(struct jsmnn * n,struct order * order)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
json_parse_upd_order(struct jsmnn * n,struct order * order)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
json_free_order(struct order * order)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
json_parse_capaths(struct jsmnn * n,struct capaths * p)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
json_free_capaths(struct capaths * p)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 *
json_parse(const char * buf,size_t sz)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 *
json_fmt_chkacc(void)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 *
json_fmt_newacc(const char * contact)621 json_fmt_newacc(const char *contact)
622 {
623 	int	 c;
624 	char	*p, *cnt = NULL;
625 
626 	if (contact != NULL) {
627 		c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
628 		if (c == -1) {
629 			warn("asprintf");
630 			return NULL;
631 		}
632 	}
633 
634 	c = asprintf(&p, "{"
635 	    "%s"
636 	    "\"termsOfServiceAgreed\": true"
637 	    "}", cnt == NULL ? "" : cnt);
638 	free(cnt);
639 	if (c == -1) {
640 		warn("asprintf");
641 		p = NULL;
642 	}
643 	return p;
644 }
645 
646 /*
647  * Format the "newOrder" resource request
648  */
649 char *
json_fmt_neworder(const char * const * alts,size_t altsz)650 json_fmt_neworder(const char *const *alts, size_t altsz)
651 {
652 	size_t	 i;
653 	int	 c;
654 	char	*p, *t;
655 
656 	if ((p = strdup("{ \"identifiers\": [")) == NULL)
657 		goto err;
658 
659 	t = p;
660 	for (i = 0; i < altsz; i++) {
661 		c = asprintf(&p,
662 		    "%s { \"type\": \"dns\", \"value\": \"%s\" }%s",
663 		    t, alts[i], i + 1 == altsz ? "" : ",");
664 		free(t);
665 		if (c == -1) {
666 			warn("asprintf");
667 			p = NULL;
668 			goto err;
669 		}
670 		t = p;
671 	}
672 	c = asprintf(&p, "%s ] }", t);
673 	free(t);
674 	if (c == -1) {
675 		warn("asprintf");
676 		p = NULL;
677 	}
678 	return p;
679 err:
680 	free(p);
681 	return NULL;
682 }
683 
684 /*
685  * Format the revoke resource request.
686  */
687 char *
json_fmt_revokecert(const char * cert)688 json_fmt_revokecert(const char *cert)
689 {
690 	int	 c;
691 	char	*p;
692 
693 	c = asprintf(&p, "{"
694 	    "\"certificate\": \"%s\""
695 	    "}",
696 	    cert);
697 	if (c == -1) {
698 		warn("asprintf");
699 		p = NULL;
700 	}
701 	return p;
702 }
703 
704 /*
705  * Format the "new-cert" resource request.
706  */
707 char *
json_fmt_newcert(const char * cert)708 json_fmt_newcert(const char *cert)
709 {
710 	int	 c;
711 	char	*p;
712 
713 	c = asprintf(&p, "{"
714 	    "\"csr\": \"%s\""
715 	    "}",
716 	    cert);
717 	if (c == -1) {
718 		warn("asprintf");
719 		p = NULL;
720 	}
721 	return p;
722 }
723 
724 /*
725  * Protected component of json_fmt_signed().
726  */
727 char *
json_fmt_protected_rsa(const char * exp,const char * mod,const char * nce,const char * url)728 json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce,
729     const char *url)
730 {
731 	int	 c;
732 	char	*p;
733 
734 	c = asprintf(&p, "{"
735 	    "\"alg\": \"RS256\", "
736 	    "\"jwk\": "
737 	    "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, "
738 	    "\"nonce\": \"%s\", "
739 	    "\"url\": \"%s\""
740 	    "}",
741 	    exp, mod, nce, url);
742 	if (c == -1) {
743 		warn("asprintf");
744 		p = NULL;
745 	}
746 	return p;
747 }
748 
749 /*
750  * Protected component of json_fmt_signed().
751  */
752 char *
json_fmt_protected_ec(const char * x,const char * y,const char * nce,const char * url)753 json_fmt_protected_ec(const char *x, const char *y, const char *nce,
754     const char *url)
755 {
756 	int	 c;
757 	char	*p;
758 
759 	c = asprintf(&p, "{"
760 	    "\"alg\": \"ES384\", "
761 	    "\"jwk\": "
762 	    "{\"crv\": \"P-384\", \"kty\": \"EC\", \"x\": \"%s\", "
763 	    "\"y\": \"%s\"}, \"nonce\": \"%s\", \"url\": \"%s\""
764 	    "}",
765 	    x, y, nce, url);
766 	if (c == -1) {
767 		warn("asprintf");
768 		p = NULL;
769 	}
770 	return p;
771 }
772 
773 /*
774  * Protected component of json_fmt_signed().
775  */
776 char *
json_fmt_protected_kid(const char * alg,const char * kid,const char * nce,const char * url)777 json_fmt_protected_kid(const char *alg, const char *kid, const char *nce,
778     const char *url)
779 {
780 	int	 c;
781 	char	*p;
782 
783 	c = asprintf(&p, "{"
784 	    "\"alg\": \"%s\", "
785 	    "\"kid\": \"%s\", "
786 	    "\"nonce\": \"%s\", "
787 	    "\"url\": \"%s\""
788 	    "}",
789 	    alg, kid, nce, url);
790 	if (c == -1) {
791 		warn("asprintf");
792 		p = NULL;
793 	}
794 	return p;
795 }
796 
797 /*
798  * Signed message contents for the CA server.
799  */
800 char *
json_fmt_signed(const char * protected,const char * payload,const char * digest)801 json_fmt_signed(const char *protected, const char *payload, const char *digest)
802 {
803 	int	 c;
804 	char	*p;
805 
806 	c = asprintf(&p, "{"
807 	    "\"protected\": \"%s\", "
808 	    "\"payload\": \"%s\", "
809 	    "\"signature\": \"%s\""
810 	    "}",
811 	    protected, payload, digest);
812 	if (c == -1) {
813 		warn("asprintf");
814 		p = NULL;
815 	}
816 	return p;
817 }
818 
819 /*
820  * Produce thumbprint input.
821  * This isn't technically a JSON string--it's the input we'll use for
822  * hashing and digesting.
823  * However, it's in the form of a JSON string, so do it here.
824  */
825 char *
json_fmt_thumb_rsa(const char * exp,const char * mod)826 json_fmt_thumb_rsa(const char *exp, const char *mod)
827 {
828 	int	 c;
829 	char	*p;
830 
831 	/*NOTE: WHITESPACE IS IMPORTANT. */
832 
833 	c = asprintf(&p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}",
834 	    exp, mod);
835 	if (c == -1) {
836 		warn("asprintf");
837 		p = NULL;
838 	}
839 	return p;
840 }
841 
842 /*
843  * Produce thumbprint input.
844  * This isn't technically a JSON string--it's the input we'll use for
845  * hashing and digesting.
846  * However, it's in the form of a JSON string, so do it here.
847  */
848 char *
json_fmt_thumb_ec(const char * x,const char * y)849 json_fmt_thumb_ec(const char *x, const char *y)
850 {
851 	int	 c;
852 	char	*p;
853 
854 	/*NOTE: WHITESPACE IS IMPORTANT. */
855 
856 	c = asprintf(&p, "{\"crv\":\"P-384\",\"kty\":\"EC\",\"x\":\"%s\","
857 	    "\"y\":\"%s\"}",
858 	    x, y);
859 	if (c == -1) {
860 		warn("asprintf");
861 		p = NULL;
862 	}
863 	return p;
864 }
865