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
29struct	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 */
36struct	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 */
51struct	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 */
59struct	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 */
70static ssize_t
71build(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 */
148static void
149jsmnparse_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 */
183static struct jsmnn *
184jsmntree_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 */
214void
215json_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 */
225static struct jsmnn *
226json_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 */
235static char *
236json_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 */
246static struct jsmnn *
247json_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 */
273static struct jsmnn *
274json_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 */
300char *
301json_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 */
331void
332json_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 */
344enum chngstatus
345json_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 */
373int
374json_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
412static enum orderstatus
413json_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 */
441int
442json_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;
483err:
484	json_free_order(order);
485	return 0;
486}
487
488int
489json_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
500void
501json_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 */
520int
521json_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 */
538void
539json_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 */
553struct jsmnn *
554json_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. */
571again:
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 */
600char *
601json_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 */
620char *
621json_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 */
649char *
650json_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;
679err:
680	free(p);
681	return NULL;
682}
683
684/*
685 * Format the revoke resource request.
686 */
687char *
688json_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 */
707char *
708json_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 */
727char *
728json_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 */
752char *
753json_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 */
776char *
777json_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 */
800char *
801json_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 */
825char *
826json_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 */
848char *
849json_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