xref: /openbsd-src/usr.sbin/acme-client/json.c (revision 6736ff2b7d5e80caf05b222894ddde9153fd72c8)
1*6736ff2bSflorian /*	$Id: json.c,v 1.21 2020/09/14 16:00:17 florian Exp $ */
2de579d12Sflorian /*
3de579d12Sflorian  * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
4de579d12Sflorian  *
5de579d12Sflorian  * Permission to use, copy, modify, and distribute this software for any
6de579d12Sflorian  * purpose with or without fee is hereby granted, provided that the above
7de579d12Sflorian  * copyright notice and this permission notice appear in all copies.
8de579d12Sflorian  *
9de579d12Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10de579d12Sflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11de579d12Sflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12de579d12Sflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13de579d12Sflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14de579d12Sflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15de579d12Sflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16de579d12Sflorian  */
17de579d12Sflorian 
18de579d12Sflorian #include <assert.h>
19de579d12Sflorian #include <err.h>
20de579d12Sflorian #include <stdarg.h>
21de579d12Sflorian #include <stdio.h>
22de579d12Sflorian #include <stdlib.h>
23de579d12Sflorian #include <string.h>
24de579d12Sflorian #include <unistd.h>
25de579d12Sflorian 
26de579d12Sflorian #include "jsmn.h"
27de579d12Sflorian #include "extern.h"
28de579d12Sflorian 
29de579d12Sflorian struct	jsmnp;
30de579d12Sflorian 
31de579d12Sflorian /*
32de579d12Sflorian  * A node in the JSMN parse tree.
33de579d12Sflorian  * Each of this corresponds to an object in the original JSMN token
34de579d12Sflorian  * list, although the contents have been extracted properly.
35de579d12Sflorian  */
36de579d12Sflorian struct	jsmnn {
37de579d12Sflorian 	struct parse	*p; /* parser object */
38de579d12Sflorian 	union {
39de579d12Sflorian 		char *str; /* JSMN_PRIMITIVE, JSMN_STRING */
40de579d12Sflorian 		struct jsmnp *obj; /* JSMN_OBJECT */
41de579d12Sflorian 		struct jsmnn **array; /* JSMN_ARRAY */
42de579d12Sflorian 	} d;
43de579d12Sflorian 	size_t		 fields; /* entries in "d" */
44de579d12Sflorian 	jsmntype_t	 type; /* type of node */
45de579d12Sflorian };
46de579d12Sflorian 
47de579d12Sflorian /*
48de579d12Sflorian  * Objects consist of node pairs: the left-hand side (before the colon)
49de579d12Sflorian  * and the right-hand side---the data.
50de579d12Sflorian  */
51de579d12Sflorian struct	jsmnp {
52de579d12Sflorian 	struct jsmnn	*lhs; /* left of colon */
53de579d12Sflorian 	struct jsmnn	*rhs; /* right of colon */
54de579d12Sflorian };
55de579d12Sflorian 
56de579d12Sflorian /*
57de579d12Sflorian  * Object for converting the JSMN token array into a tree.
58de579d12Sflorian  */
59de579d12Sflorian struct	parse {
60de579d12Sflorian 	struct jsmnn	*nodes; /* all nodes */
61de579d12Sflorian 	size_t		 cur; /* current number */
62de579d12Sflorian 	size_t		 max; /* nodes in "nodes" */
63de579d12Sflorian };
64de579d12Sflorian 
65de579d12Sflorian /*
66de579d12Sflorian  * Recursive part for convertin a JSMN token array into a tree.
67de579d12Sflorian  * See "example/jsondump.c" for its construction (it's the same except
68de579d12Sflorian  * for how it handles allocation errors).
69de579d12Sflorian  */
70de579d12Sflorian static ssize_t
build(struct parse * parse,struct jsmnn ** np,jsmntok_t * t,const char * js,size_t sz)71de579d12Sflorian build(struct parse *parse, struct jsmnn **np,
72de579d12Sflorian     jsmntok_t *t, const char *js, size_t sz)
73de579d12Sflorian {
74de579d12Sflorian 	size_t		 i, j;
75de579d12Sflorian 	struct jsmnn	*n;
76de579d12Sflorian 	ssize_t		 tmp;
77de579d12Sflorian 
787cd8f039Sjsing 	if (sz == 0)
7934335c11Sjsing 		return 0;
80de579d12Sflorian 
81de579d12Sflorian 	assert(parse->cur < parse->max);
82de579d12Sflorian 	n = *np = &parse->nodes[parse->cur++];
83de579d12Sflorian 	n->p = parse;
84de579d12Sflorian 	n->type = t->type;
85de579d12Sflorian 
86de579d12Sflorian 	switch (t->type) {
87a8699559Sderaadt 	case JSMN_STRING:
88de579d12Sflorian 		/* FALLTHROUGH */
89a8699559Sderaadt 	case JSMN_PRIMITIVE:
90de579d12Sflorian 		n->fields = 1;
91de579d12Sflorian 		n->d.str = strndup
92de579d12Sflorian 			(js + t->start,
93de579d12Sflorian 			 t->end - t->start);
947cd8f039Sjsing 		if (n->d.str == NULL)
95de579d12Sflorian 			break;
9634335c11Sjsing 		return 1;
97a8699559Sderaadt 	case JSMN_OBJECT:
98de579d12Sflorian 		n->fields = t->size;
99de579d12Sflorian 		n->d.obj = calloc(n->fields,
100de579d12Sflorian 			sizeof(struct jsmnp));
1017cd8f039Sjsing 		if (n->d.obj == NULL)
102de579d12Sflorian 			break;
103de579d12Sflorian 		for (i = j = 0; i < (size_t)t->size; i++) {
104de579d12Sflorian 			tmp = build(parse,
105de579d12Sflorian 				&n->d.obj[i].lhs,
106de579d12Sflorian 				t + 1 + j, js, sz - j);
107de579d12Sflorian 			if (tmp < 0)
108de579d12Sflorian 				break;
109de579d12Sflorian 			j += tmp;
110de579d12Sflorian 			tmp = build(parse,
111de579d12Sflorian 				&n->d.obj[i].rhs,
112de579d12Sflorian 				t + 1 + j, js, sz - j);
113de579d12Sflorian 			if (tmp < 0)
114de579d12Sflorian 				break;
115de579d12Sflorian 			j += tmp;
116de579d12Sflorian 		}
117de579d12Sflorian 		if (i < (size_t)t->size)
118de579d12Sflorian 			break;
11934335c11Sjsing 		return j + 1;
120a8699559Sderaadt 	case JSMN_ARRAY:
121de579d12Sflorian 		n->fields = t->size;
122de579d12Sflorian 		n->d.array = calloc(n->fields,
123de579d12Sflorian 			sizeof(struct jsmnn *));
1247cd8f039Sjsing 		if (n->d.array == NULL)
125de579d12Sflorian 			break;
126de579d12Sflorian 		for (i = j = 0; i < (size_t)t->size; i++) {
127de579d12Sflorian 			tmp = build(parse,
128de579d12Sflorian 				&n->d.array[i],
129de579d12Sflorian 				t + 1 + j, js, sz - j);
130de579d12Sflorian 			if (tmp < 0)
131de579d12Sflorian 				break;
132de579d12Sflorian 			j += tmp;
133de579d12Sflorian 		}
134de579d12Sflorian 		if (i < (size_t)t->size)
135de579d12Sflorian 			break;
13634335c11Sjsing 		return j + 1;
137de579d12Sflorian 	default:
138de579d12Sflorian 		break;
139de579d12Sflorian 	}
140de579d12Sflorian 
14134335c11Sjsing 	return -1;
142de579d12Sflorian }
143de579d12Sflorian 
144de579d12Sflorian /*
145de579d12Sflorian  * Fully free up a parse sequence.
146de579d12Sflorian  * This handles all nodes sequentially, not recursively.
147de579d12Sflorian  */
148de579d12Sflorian static void
jsmnparse_free(struct parse * p)149de579d12Sflorian jsmnparse_free(struct parse *p)
150de579d12Sflorian {
151de579d12Sflorian 	size_t	 i;
152de579d12Sflorian 
1537cd8f039Sjsing 	if (p == NULL)
154de579d12Sflorian 		return;
155cd15ff9aStedu 	for (i = 0; i < p->max; i++) {
156cd15ff9aStedu 		struct jsmnn	*n = &p->nodes[i];
157cd15ff9aStedu 		switch (n->type) {
158cd15ff9aStedu 		case JSMN_ARRAY:
159cd15ff9aStedu 			free(n->d.array);
160cd15ff9aStedu 			break;
161cd15ff9aStedu 		case JSMN_OBJECT:
162cd15ff9aStedu 			free(n->d.obj);
163cd15ff9aStedu 			break;
164cd15ff9aStedu 		case JSMN_PRIMITIVE:
165cd15ff9aStedu 			free(n->d.str);
166cd15ff9aStedu 			break;
167cd15ff9aStedu 		case JSMN_STRING:
168cd15ff9aStedu 			free(n->d.str);
169cd15ff9aStedu 			break;
170cd15ff9aStedu 		case JSMN_UNDEFINED:
171cd15ff9aStedu 			break;
172cd15ff9aStedu 		}
173cd15ff9aStedu 	}
174de579d12Sflorian 	free(p->nodes);
175de579d12Sflorian 	free(p);
176de579d12Sflorian }
177de579d12Sflorian 
178de579d12Sflorian /*
179de579d12Sflorian  * Allocate a tree representation of "t".
180de579d12Sflorian  * This returns NULL on allocation failure or when sz is zero, in which
181de579d12Sflorian  * case all resources allocated along the way are freed already.
182de579d12Sflorian  */
183de579d12Sflorian static struct jsmnn *
jsmntree_alloc(jsmntok_t * t,const char * js,size_t sz)184de579d12Sflorian jsmntree_alloc(jsmntok_t *t, const char *js, size_t sz)
185de579d12Sflorian {
186de579d12Sflorian 	struct jsmnn	*first;
187de579d12Sflorian 	struct parse	*p;
188de579d12Sflorian 
1897cd8f039Sjsing 	if (sz == 0)
19034335c11Sjsing 		return NULL;
191de579d12Sflorian 
192de579d12Sflorian 	p = calloc(1, sizeof(struct parse));
1937cd8f039Sjsing 	if (p == NULL)
19434335c11Sjsing 		return NULL;
195de579d12Sflorian 
196de579d12Sflorian 	p->max = sz;
197de579d12Sflorian 	p->nodes = calloc(p->max, sizeof(struct jsmnn));
1987cd8f039Sjsing 	if (p->nodes == NULL) {
199de579d12Sflorian 		free(p);
20034335c11Sjsing 		return NULL;
201de579d12Sflorian 	}
202de579d12Sflorian 
203de579d12Sflorian 	if (build(p, &first, t, js, sz) < 0) {
204de579d12Sflorian 		jsmnparse_free(p);
205de579d12Sflorian 		first = NULL;
206de579d12Sflorian 	}
207de579d12Sflorian 
20834335c11Sjsing 	return first;
209de579d12Sflorian }
210de579d12Sflorian 
211de579d12Sflorian /*
212de579d12Sflorian  * Call through to free parse contents.
213de579d12Sflorian  */
214de579d12Sflorian void
json_free(struct jsmnn * first)215de579d12Sflorian json_free(struct jsmnn *first)
216de579d12Sflorian {
217de579d12Sflorian 
2187cd8f039Sjsing 	if (first != NULL)
219de579d12Sflorian 		jsmnparse_free(first->p);
220de579d12Sflorian }
221de579d12Sflorian 
222de579d12Sflorian /*
223de579d12Sflorian  * Just check that the array object is in fact an object.
224de579d12Sflorian  */
225de579d12Sflorian static struct jsmnn *
json_getarrayobj(struct jsmnn * n)226de579d12Sflorian json_getarrayobj(struct jsmnn *n)
227de579d12Sflorian {
228de579d12Sflorian 
22934335c11Sjsing 	return n->type != JSMN_OBJECT ? NULL : n;
230de579d12Sflorian }
231de579d12Sflorian 
232de579d12Sflorian /*
2337b00f4e9Sflorian  * Get a string element from an array
2347b00f4e9Sflorian  */
2357b00f4e9Sflorian static char *
json_getarraystr(struct jsmnn * n)2367b00f4e9Sflorian json_getarraystr(struct jsmnn *n)
2377b00f4e9Sflorian {
2387b00f4e9Sflorian 	return n->type != JSMN_STRING ? NULL : n->d.str;
2397b00f4e9Sflorian }
2407b00f4e9Sflorian 
2417b00f4e9Sflorian /*
242de579d12Sflorian  * Extract an array from the returned JSON object, making sure that it's
243de579d12Sflorian  * the correct type.
244de579d12Sflorian  * Returns NULL on failure.
245de579d12Sflorian  */
246de579d12Sflorian static struct jsmnn *
json_getarray(struct jsmnn * n,const char * name)247de579d12Sflorian json_getarray(struct jsmnn *n, const char *name)
248de579d12Sflorian {
249de579d12Sflorian 	size_t		 i;
250de579d12Sflorian 
2517cd8f039Sjsing 	if (n->type != JSMN_OBJECT)
25234335c11Sjsing 		return NULL;
253de579d12Sflorian 	for (i = 0; i < n->fields; i++) {
2547cd8f039Sjsing 		if (n->d.obj[i].lhs->type != JSMN_STRING &&
2557cd8f039Sjsing 		    n->d.obj[i].lhs->type != JSMN_PRIMITIVE)
256de579d12Sflorian 			continue;
257de579d12Sflorian 		else if (strcmp(name, n->d.obj[i].lhs->d.str))
258de579d12Sflorian 			continue;
259de579d12Sflorian 		break;
260de579d12Sflorian 	}
261de579d12Sflorian 	if (i == n->fields)
26234335c11Sjsing 		return NULL;
2637cd8f039Sjsing 	if (n->d.obj[i].rhs->type != JSMN_ARRAY)
26434335c11Sjsing 		return NULL;
26534335c11Sjsing 	return n->d.obj[i].rhs;
266de579d12Sflorian }
267de579d12Sflorian 
268de579d12Sflorian /*
2690b28b247Sflorian  * Extract subtree from the returned JSON object, making sure that it's
2700b28b247Sflorian  * the correct type.
2710b28b247Sflorian  * Returns NULL on failure.
2720b28b247Sflorian  */
2730b28b247Sflorian static struct jsmnn *
json_getobj(struct jsmnn * n,const char * name)2740b28b247Sflorian json_getobj(struct jsmnn *n, const char *name)
2750b28b247Sflorian {
2760b28b247Sflorian 	size_t		 i;
2770b28b247Sflorian 
2780b28b247Sflorian 	if (n->type != JSMN_OBJECT)
2790b28b247Sflorian 		return NULL;
2800b28b247Sflorian 	for (i = 0; i < n->fields; i++) {
2810b28b247Sflorian 		if (n->d.obj[i].lhs->type != JSMN_STRING &&
2820b28b247Sflorian 		    n->d.obj[i].lhs->type != JSMN_PRIMITIVE)
2830b28b247Sflorian 			continue;
2840b28b247Sflorian 		else if (strcmp(name, n->d.obj[i].lhs->d.str))
2850b28b247Sflorian 			continue;
2860b28b247Sflorian 		break;
2870b28b247Sflorian 	}
2880b28b247Sflorian 	if (i == n->fields)
2890b28b247Sflorian 		return NULL;
2900b28b247Sflorian 	if (n->d.obj[i].rhs->type != JSMN_OBJECT)
2910b28b247Sflorian 		return NULL;
2920b28b247Sflorian 	return n->d.obj[i].rhs;
2930b28b247Sflorian }
2940b28b247Sflorian 
2950b28b247Sflorian /*
296de579d12Sflorian  * Extract a single string from the returned JSON object, making sure
297de579d12Sflorian  * that it's the correct type.
298de579d12Sflorian  * Returns NULL on failure.
299de579d12Sflorian  */
300ec77e55dSflorian char *
json_getstr(struct jsmnn * n,const char * name)301de579d12Sflorian json_getstr(struct jsmnn *n, const char *name)
302de579d12Sflorian {
303de579d12Sflorian 	size_t		 i;
304de579d12Sflorian 	char		*cp;
305de579d12Sflorian 
3067cd8f039Sjsing 	if (n->type != JSMN_OBJECT)
30734335c11Sjsing 		return NULL;
308de579d12Sflorian 	for (i = 0; i < n->fields; i++) {
3097cd8f039Sjsing 		if (n->d.obj[i].lhs->type != JSMN_STRING &&
3107cd8f039Sjsing 		    n->d.obj[i].lhs->type != JSMN_PRIMITIVE)
311de579d12Sflorian 			continue;
312de579d12Sflorian 		else if (strcmp(name, n->d.obj[i].lhs->d.str))
313de579d12Sflorian 			continue;
314de579d12Sflorian 		break;
315de579d12Sflorian 	}
316de579d12Sflorian 	if (i == n->fields)
31734335c11Sjsing 		return NULL;
3187cd8f039Sjsing 	if (n->d.obj[i].rhs->type != JSMN_STRING &&
3197cd8f039Sjsing 	    n->d.obj[i].rhs->type != JSMN_PRIMITIVE)
32034335c11Sjsing 		return NULL;
321de579d12Sflorian 
322de579d12Sflorian 	cp = strdup(n->d.obj[i].rhs->d.str);
3237cd8f039Sjsing 	if (cp == NULL)
324de579d12Sflorian 		warn("strdup");
32534335c11Sjsing 	return cp;
326de579d12Sflorian }
327de579d12Sflorian 
328de579d12Sflorian /*
329de579d12Sflorian  * Completely free the challenge response body.
330de579d12Sflorian  */
331de579d12Sflorian void
json_free_challenge(struct chng * p)332de579d12Sflorian json_free_challenge(struct chng *p)
333de579d12Sflorian {
334de579d12Sflorian 
335de579d12Sflorian 	free(p->uri);
336de579d12Sflorian 	free(p->token);
337de579d12Sflorian 	p->uri = p->token = NULL;
338de579d12Sflorian }
339de579d12Sflorian 
340de579d12Sflorian /*
341de579d12Sflorian  * Parse the response from the ACME server when we're waiting to see
342de579d12Sflorian  * whether the challenge has been ok.
343de579d12Sflorian  */
344045b9945Sbenno enum chngstatus
json_parse_response(struct jsmnn * n)345de579d12Sflorian json_parse_response(struct jsmnn *n)
346de579d12Sflorian {
347de579d12Sflorian 	char		*resp;
348045b9945Sbenno 	enum chngstatus	 rc;
349de579d12Sflorian 
3507cd8f039Sjsing 	if (n == NULL)
351045b9945Sbenno 		return CHNG_INVALID;
3527cd8f039Sjsing 	if ((resp = json_getstr(n, "status")) == NULL)
353045b9945Sbenno 		return CHNG_INVALID;
354de579d12Sflorian 
3557cd8f039Sjsing 	if (strcmp(resp, "valid") == 0)
356045b9945Sbenno 		rc = CHNG_VALID;
3577cd8f039Sjsing 	else if (strcmp(resp, "pending") == 0)
358045b9945Sbenno 		rc = CHNG_PENDING;
3597b00f4e9Sflorian 	else if (strcmp(resp, "processing") == 0)
3607b00f4e9Sflorian 		rc = CHNG_PROCESSING;
361de579d12Sflorian 	else
362045b9945Sbenno 		rc = CHNG_INVALID;
363de579d12Sflorian 
364de579d12Sflorian 	free(resp);
36534335c11Sjsing 	return rc;
366de579d12Sflorian }
367de579d12Sflorian 
368de579d12Sflorian /*
369de579d12Sflorian  * Parse the response from a new-authz, which consists of challenge
370de579d12Sflorian  * information, into a structure.
371de579d12Sflorian  * We only care about the HTTP-01 response.
372de579d12Sflorian  */
373de579d12Sflorian int
json_parse_challenge(struct jsmnn * n,struct chng * p)374de579d12Sflorian json_parse_challenge(struct jsmnn *n, struct chng *p)
375de579d12Sflorian {
37642c2cc51Sflorian 	struct jsmnn	*array, *obj, *error;
377de579d12Sflorian 	size_t		 i;
378de579d12Sflorian 	int		 rc;
379de579d12Sflorian 	char		*type;
380de579d12Sflorian 
3817cd8f039Sjsing 	if (n == NULL)
38234335c11Sjsing 		return 0;
383de579d12Sflorian 
384de579d12Sflorian 	array = json_getarray(n, "challenges");
3857cd8f039Sjsing 	if (array == NULL)
38634335c11Sjsing 		return 0;
387de579d12Sflorian 
388de579d12Sflorian 	for (i = 0; i < array->fields; i++) {
389de579d12Sflorian 		obj = json_getarrayobj(array->d.array[i]);
3907cd8f039Sjsing 		if (obj == NULL)
391de579d12Sflorian 			continue;
392de579d12Sflorian 		type = json_getstr(obj, "type");
3937cd8f039Sjsing 		if (type == NULL)
394de579d12Sflorian 			continue;
395de579d12Sflorian 		rc = strcmp(type, "http-01");
396de579d12Sflorian 		free(type);
397de579d12Sflorian 		if (rc)
398de579d12Sflorian 			continue;
3997b00f4e9Sflorian 		p->uri = json_getstr(obj, "url");
400de579d12Sflorian 		p->token = json_getstr(obj, "token");
4017b00f4e9Sflorian 		p->status = json_parse_response(obj);
40242c2cc51Sflorian 		if (p->status == CHNG_INVALID) {
40342c2cc51Sflorian 			error = json_getobj(obj, "error");
40442c2cc51Sflorian 			p->error = json_getstr(error, "detail");
40542c2cc51Sflorian 		}
40634335c11Sjsing 		return p->uri != NULL && p->token != NULL;
407de579d12Sflorian 	}
408de579d12Sflorian 
40934335c11Sjsing 	return 0;
410de579d12Sflorian }
411de579d12Sflorian 
4127b00f4e9Sflorian static enum orderstatus
json_parse_order_status(struct jsmnn * n)4137b00f4e9Sflorian json_parse_order_status(struct jsmnn *n)
4147b00f4e9Sflorian {
4157b00f4e9Sflorian 	char	*status;
4167b00f4e9Sflorian 
4177b00f4e9Sflorian 	if (n == NULL)
4187b00f4e9Sflorian 		return ORDER_INVALID;
4197b00f4e9Sflorian 
4207b00f4e9Sflorian 	if ((status = json_getstr(n, "status")) == NULL)
4217b00f4e9Sflorian 		return ORDER_INVALID;
4227b00f4e9Sflorian 
4237b00f4e9Sflorian 	if (strcmp(status, "pending") == 0)
4247b00f4e9Sflorian 		return ORDER_PENDING;
4257b00f4e9Sflorian 	else if (strcmp(status, "ready") == 0)
4267b00f4e9Sflorian 		return ORDER_READY;
4277b00f4e9Sflorian 	else if (strcmp(status, "processing") == 0)
4287b00f4e9Sflorian 		return ORDER_PROCESSING;
4297b00f4e9Sflorian 	else if (strcmp(status, "valid") == 0)
4307b00f4e9Sflorian 		return ORDER_VALID;
4317b00f4e9Sflorian 	else if (strcmp(status, "invalid") == 0)
4327b00f4e9Sflorian 		return ORDER_INVALID;
4337b00f4e9Sflorian 	else
4347b00f4e9Sflorian 		return ORDER_INVALID;
4357b00f4e9Sflorian }
4367b00f4e9Sflorian 
4377b00f4e9Sflorian /*
4387b00f4e9Sflorian  * Parse the response from a newOrder, which consists of a status
4397b00f4e9Sflorian  * a list of authorization urls and a finalize url into a struct.
4407b00f4e9Sflorian  */
4417b00f4e9Sflorian int
json_parse_order(struct jsmnn * n,struct order * order)4427b00f4e9Sflorian json_parse_order(struct jsmnn *n, struct order *order)
4437b00f4e9Sflorian {
4447b00f4e9Sflorian 	struct jsmnn	*array;
4457b00f4e9Sflorian 	size_t		 i;
4467b00f4e9Sflorian 	char		*finalize, *str;
4477b00f4e9Sflorian 
4487b00f4e9Sflorian 	order->status = json_parse_order_status(n);
4497b00f4e9Sflorian 
4507b00f4e9Sflorian 	if (n == NULL)
4517b00f4e9Sflorian 		return 0;
4527b00f4e9Sflorian 
4537b00f4e9Sflorian 	if ((finalize = json_getstr(n, "finalize")) == NULL) {
4547b00f4e9Sflorian 		warnx("no finalize field in order response");
4557b00f4e9Sflorian 		return 0;
4567b00f4e9Sflorian 	}
4577b00f4e9Sflorian 
4587b00f4e9Sflorian 	if ((order->finalize = strdup(finalize)) == NULL)
4597b00f4e9Sflorian 		goto err;
4607b00f4e9Sflorian 
4617b00f4e9Sflorian 	if ((array = json_getarray(n, "authorizations")) == NULL)
4627b00f4e9Sflorian 		goto err;
4637b00f4e9Sflorian 
464ba08a668Stedu 	if (array->fields > 0) {
4657f1c0488Sflorian 		order->auths = calloc(array->fields, sizeof(*order->auths));
4667b00f4e9Sflorian 		if (order->auths == NULL) {
4677b00f4e9Sflorian 			warn("malloc");
4687b00f4e9Sflorian 			goto err;
4697b00f4e9Sflorian 		}
470ba08a668Stedu 		order->authsz = array->fields;
4717b00f4e9Sflorian 	}
4727b00f4e9Sflorian 
4737b00f4e9Sflorian 	for (i = 0; i < array->fields; i++) {
4747b00f4e9Sflorian 		str = json_getarraystr(array->d.array[i]);
4757b00f4e9Sflorian 		if (str == NULL)
4767b00f4e9Sflorian 			continue;
4777b00f4e9Sflorian 		if ((order->auths[i] = strdup(str)) == NULL) {
4787b00f4e9Sflorian 			warn("strdup");
4797b00f4e9Sflorian 			goto err;
4807b00f4e9Sflorian 		}
4817b00f4e9Sflorian 	}
4827b00f4e9Sflorian 	return 1;
4837b00f4e9Sflorian err:
4847b00f4e9Sflorian 	json_free_order(order);
4857b00f4e9Sflorian 	return 0;
4867b00f4e9Sflorian }
4877b00f4e9Sflorian 
4887b00f4e9Sflorian int
json_parse_upd_order(struct jsmnn * n,struct order * order)4897b00f4e9Sflorian json_parse_upd_order(struct jsmnn *n, struct order *order)
4907b00f4e9Sflorian {
4917b00f4e9Sflorian 	char	*certificate;
4927b00f4e9Sflorian 	order->status = json_parse_order_status(n);
4937b00f4e9Sflorian 	if ((certificate = json_getstr(n, "certificate")) != NULL) {
4947b00f4e9Sflorian 		if ((order->certificate = strdup(certificate)) == NULL)
4957b00f4e9Sflorian 			return 0;
4967b00f4e9Sflorian 	}
4977b00f4e9Sflorian 	return 1;
4987b00f4e9Sflorian }
4997b00f4e9Sflorian 
5007b00f4e9Sflorian void
json_free_order(struct order * order)5017b00f4e9Sflorian json_free_order(struct order *order)
5027b00f4e9Sflorian {
5037b00f4e9Sflorian 	size_t i;
5047b00f4e9Sflorian 
5057b00f4e9Sflorian 	free(order->finalize);
5067b00f4e9Sflorian 	order->finalize = NULL;
5077b00f4e9Sflorian 	for(i = 0; i < order->authsz; i++)
5087b00f4e9Sflorian 		free(order->auths[i]);
5097b00f4e9Sflorian 	free(order->auths);
5107b00f4e9Sflorian 
5117b00f4e9Sflorian 	order->finalize = NULL;
5127b00f4e9Sflorian 	order->auths = NULL;
5137b00f4e9Sflorian 	order->authsz = 0;
5147b00f4e9Sflorian }
5157b00f4e9Sflorian 
516de579d12Sflorian /*
517de579d12Sflorian  * Extract the CA paths from the JSON response object.
518de579d12Sflorian  * Return zero on failure, non-zero on success.
519de579d12Sflorian  */
520de579d12Sflorian int
json_parse_capaths(struct jsmnn * n,struct capaths * p)521de579d12Sflorian json_parse_capaths(struct jsmnn *n, struct capaths *p)
522de579d12Sflorian {
5237cd8f039Sjsing 	if (n == NULL)
52434335c11Sjsing 		return 0;
525de579d12Sflorian 
5267b00f4e9Sflorian 	p->newaccount = json_getstr(n, "newAccount");
5277b00f4e9Sflorian 	p->newnonce = json_getstr(n, "newNonce");
5287b00f4e9Sflorian 	p->neworder = json_getstr(n, "newOrder");
5297b00f4e9Sflorian 	p->revokecert = json_getstr(n, "revokeCert");
5300b28b247Sflorian 
5317b00f4e9Sflorian 	return p->newaccount != NULL && p->newnonce != NULL &&
5327b00f4e9Sflorian 	    p->neworder != NULL && p->revokecert != NULL;
533de579d12Sflorian }
534de579d12Sflorian 
535de579d12Sflorian /*
536de579d12Sflorian  * Free up all of our CA-noted paths (which may all be NULL).
537de579d12Sflorian  */
538de579d12Sflorian void
json_free_capaths(struct capaths * p)539de579d12Sflorian json_free_capaths(struct capaths *p)
540de579d12Sflorian {
541de579d12Sflorian 
5427b00f4e9Sflorian 	free(p->newaccount);
5437b00f4e9Sflorian 	free(p->newnonce);
5447b00f4e9Sflorian 	free(p->neworder);
545de579d12Sflorian 	free(p->revokecert);
546de579d12Sflorian 	memset(p, 0, sizeof(struct capaths));
547de579d12Sflorian }
548de579d12Sflorian 
549de579d12Sflorian /*
550de579d12Sflorian  * Parse an HTTP response body from a buffer of size "sz".
551de579d12Sflorian  * Returns an opaque pointer on success, otherwise NULL on error.
552de579d12Sflorian  */
553de579d12Sflorian struct jsmnn *
json_parse(const char * buf,size_t sz)554de579d12Sflorian json_parse(const char *buf, size_t sz)
555de579d12Sflorian {
556de579d12Sflorian 	struct jsmnn	*n;
557de579d12Sflorian 	jsmn_parser	 p;
558fd36792fSflorian 	jsmntok_t	*tok, *ntok;
559de579d12Sflorian 	int		 r;
560de579d12Sflorian 	size_t		 tokcount;
561de579d12Sflorian 
562de579d12Sflorian 	jsmn_init(&p);
563de579d12Sflorian 	tokcount = 128;
564de579d12Sflorian 
565fd36792fSflorian 	if ((tok = calloc(tokcount, sizeof(jsmntok_t))) == NULL) {
566de579d12Sflorian 		warn("calloc");
56734335c11Sjsing 		return NULL;
568de579d12Sflorian 	}
569de579d12Sflorian 
570fd36792fSflorian 	/* Do this until we don't need any more tokens. */
571fd36792fSflorian again:
572de579d12Sflorian 	/* Actually try to parse the JSON into the tokens. */
573de579d12Sflorian 	r = jsmn_parse(&p, buf, sz, tok, tokcount);
5747cd8f039Sjsing 	if (r < 0 && r == JSMN_ERROR_NOMEM) {
575fd36792fSflorian 		if ((ntok = recallocarray(tok, tokcount, tokcount * 2,
576fd36792fSflorian 		    sizeof(jsmntok_t))) == NULL) {
577fd36792fSflorian 			warn("calloc");
578de579d12Sflorian 			free(tok);
579fd36792fSflorian 			return NULL;
580fd36792fSflorian 		}
581fd36792fSflorian 		tok = ntok;
582fd36792fSflorian 		tokcount *= 2;
583de579d12Sflorian 		goto again;
584de579d12Sflorian 	} else if (r < 0) {
585de579d12Sflorian 		warnx("jsmn_parse: %d", r);
586de579d12Sflorian 		free(tok);
58734335c11Sjsing 		return NULL;
588de579d12Sflorian 	}
589de579d12Sflorian 
590de579d12Sflorian 	/* Now parse the tokens into a tree. */
591de579d12Sflorian 
592de579d12Sflorian 	n = jsmntree_alloc(tok, buf, r);
593de579d12Sflorian 	free(tok);
59434335c11Sjsing 	return n;
595de579d12Sflorian }
596de579d12Sflorian 
597de579d12Sflorian /*
5987b00f4e9Sflorian  * Format the "newAccount" resource request to check if the account exist.
599de579d12Sflorian  */
600de579d12Sflorian char *
json_fmt_chkacc(void)6017b00f4e9Sflorian json_fmt_chkacc(void)
602de579d12Sflorian {
603de579d12Sflorian 	int	 c;
604de579d12Sflorian 	char	*p;
605de579d12Sflorian 
606de579d12Sflorian 	c = asprintf(&p, "{"
6077b00f4e9Sflorian 	    "\"termsOfServiceAgreed\": true, "
6087b00f4e9Sflorian 	    "\"onlyReturnExisting\": true"
6097b00f4e9Sflorian 	    "}");
6107cd8f039Sjsing 	if (c == -1) {
611de579d12Sflorian 		warn("asprintf");
612de579d12Sflorian 		p = NULL;
613de579d12Sflorian 	}
61434335c11Sjsing 	return p;
615de579d12Sflorian }
616de579d12Sflorian 
617de579d12Sflorian /*
6187b00f4e9Sflorian  * Format the "newAccount" resource request.
619de579d12Sflorian  */
620de579d12Sflorian char *
json_fmt_newacc(const char * contact)621*6736ff2bSflorian json_fmt_newacc(const char *contact)
622de579d12Sflorian {
623de579d12Sflorian 	int	 c;
624*6736ff2bSflorian 	char	*p, *cnt = NULL;
625*6736ff2bSflorian 
626*6736ff2bSflorian 	if (contact != NULL) {
627*6736ff2bSflorian 		c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
628*6736ff2bSflorian 		if (c == -1) {
629*6736ff2bSflorian 			warn("asprintf");
630*6736ff2bSflorian 			return NULL;
631*6736ff2bSflorian 		}
632*6736ff2bSflorian 	}
633de579d12Sflorian 
634de579d12Sflorian 	c = asprintf(&p, "{"
635*6736ff2bSflorian 	    "%s"
6367b00f4e9Sflorian 	    "\"termsOfServiceAgreed\": true"
637*6736ff2bSflorian 	    "}", cnt == NULL ? "" : cnt);
638*6736ff2bSflorian 	free(cnt);
6397cd8f039Sjsing 	if (c == -1) {
640de579d12Sflorian 		warn("asprintf");
641de579d12Sflorian 		p = NULL;
642de579d12Sflorian 	}
64334335c11Sjsing 	return p;
644de579d12Sflorian }
645de579d12Sflorian 
646de579d12Sflorian /*
6477b00f4e9Sflorian  * Format the "newOrder" resource request
648de579d12Sflorian  */
649de579d12Sflorian char *
json_fmt_neworder(const char * const * alts,size_t altsz)6507b00f4e9Sflorian json_fmt_neworder(const char *const *alts, size_t altsz)
651de579d12Sflorian {
6527b00f4e9Sflorian 	size_t	 i;
653de579d12Sflorian 	int	 c;
6547b00f4e9Sflorian 	char	*p, *t;
655de579d12Sflorian 
6567b00f4e9Sflorian 	if ((p = strdup("{ \"identifiers\": [")) == NULL)
6577b00f4e9Sflorian 		goto err;
6587b00f4e9Sflorian 
6597b00f4e9Sflorian 	t = p;
6607b00f4e9Sflorian 	for (i = 0; i < altsz; i++) {
6617b00f4e9Sflorian 		c = asprintf(&p,
6627b00f4e9Sflorian 		    "%s { \"type\": \"dns\", \"value\": \"%s\" }%s",
6637b00f4e9Sflorian 		    t, alts[i], i + 1 == altsz ? "" : ",");
6647b00f4e9Sflorian 		free(t);
6657b00f4e9Sflorian 		if (c == -1) {
6667b00f4e9Sflorian 			warn("asprintf");
6677b00f4e9Sflorian 			p = NULL;
6687b00f4e9Sflorian 			goto err;
6697b00f4e9Sflorian 		}
6707b00f4e9Sflorian 		t = p;
6717b00f4e9Sflorian 	}
6727b00f4e9Sflorian 	c = asprintf(&p, "%s ] }", t);
6737b00f4e9Sflorian 	free(t);
6747cd8f039Sjsing 	if (c == -1) {
675de579d12Sflorian 		warn("asprintf");
676de579d12Sflorian 		p = NULL;
677de579d12Sflorian 	}
67834335c11Sjsing 	return p;
6797b00f4e9Sflorian err:
6807b00f4e9Sflorian 	free(p);
6817b00f4e9Sflorian 	return NULL;
682de579d12Sflorian }
683de579d12Sflorian 
684de579d12Sflorian /*
6857b00f4e9Sflorian  * Format the revoke resource request.
686de579d12Sflorian  */
687de579d12Sflorian char *
json_fmt_revokecert(const char * cert)688de579d12Sflorian json_fmt_revokecert(const char *cert)
689de579d12Sflorian {
690de579d12Sflorian 	int	 c;
691de579d12Sflorian 	char	*p;
692de579d12Sflorian 
693de579d12Sflorian 	c = asprintf(&p, "{"
694de579d12Sflorian 	    "\"certificate\": \"%s\""
69555599e87Sderaadt 	    "}",
69655599e87Sderaadt 	    cert);
6977cd8f039Sjsing 	if (c == -1) {
698de579d12Sflorian 		warn("asprintf");
699de579d12Sflorian 		p = NULL;
700de579d12Sflorian 	}
70134335c11Sjsing 	return p;
702de579d12Sflorian }
703de579d12Sflorian 
704de579d12Sflorian /*
705de579d12Sflorian  * Format the "new-cert" resource request.
706de579d12Sflorian  */
707de579d12Sflorian char *
json_fmt_newcert(const char * cert)708de579d12Sflorian json_fmt_newcert(const char *cert)
709de579d12Sflorian {
710de579d12Sflorian 	int	 c;
711de579d12Sflorian 	char	*p;
712de579d12Sflorian 
713de579d12Sflorian 	c = asprintf(&p, "{"
714de579d12Sflorian 	    "\"csr\": \"%s\""
71555599e87Sderaadt 	    "}",
71655599e87Sderaadt 	    cert);
7177cd8f039Sjsing 	if (c == -1) {
718de579d12Sflorian 		warn("asprintf");
719de579d12Sflorian 		p = NULL;
720de579d12Sflorian 	}
72134335c11Sjsing 	return p;
722de579d12Sflorian }
723de579d12Sflorian 
724de579d12Sflorian /*
7257b00f4e9Sflorian  * Protected component of json_fmt_signed().
726de579d12Sflorian  */
727de579d12Sflorian char *
json_fmt_protected_rsa(const char * exp,const char * mod,const char * nce,const char * url)7287b00f4e9Sflorian json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce,
7297b00f4e9Sflorian     const char *url)
730de579d12Sflorian {
731de579d12Sflorian 	int	 c;
732de579d12Sflorian 	char	*p;
733de579d12Sflorian 
734de579d12Sflorian 	c = asprintf(&p, "{"
735de579d12Sflorian 	    "\"alg\": \"RS256\", "
736de579d12Sflorian 	    "\"jwk\": "
7377b00f4e9Sflorian 	    "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, "
7387b00f4e9Sflorian 	    "\"nonce\": \"%s\", "
7397b00f4e9Sflorian 	    "\"url\": \"%s\""
74055599e87Sderaadt 	    "}",
7417b00f4e9Sflorian 	    exp, mod, nce, url);
7427cd8f039Sjsing 	if (c == -1) {
743de579d12Sflorian 		warn("asprintf");
744de579d12Sflorian 		p = NULL;
745de579d12Sflorian 	}
74634335c11Sjsing 	return p;
747de579d12Sflorian }
748de579d12Sflorian 
749de579d12Sflorian /*
750de579d12Sflorian  * Protected component of json_fmt_signed().
751de579d12Sflorian  */
752de579d12Sflorian char *
json_fmt_protected_ec(const char * x,const char * y,const char * nce,const char * url)7534f8b772fSflorian json_fmt_protected_ec(const char *x, const char *y, const char *nce,
7544f8b772fSflorian     const char *url)
755de579d12Sflorian {
756de579d12Sflorian 	int	 c;
757de579d12Sflorian 	char	*p;
758de579d12Sflorian 
759de579d12Sflorian 	c = asprintf(&p, "{"
7604f8b772fSflorian 	    "\"alg\": \"ES384\", "
7614f8b772fSflorian 	    "\"jwk\": "
7624f8b772fSflorian 	    "{\"crv\": \"P-384\", \"kty\": \"EC\", \"x\": \"%s\", "
7634f8b772fSflorian 	    "\"y\": \"%s\"}, \"nonce\": \"%s\", \"url\": \"%s\""
7644f8b772fSflorian 	    "}",
7654f8b772fSflorian 	    x, y, nce, url);
7664f8b772fSflorian 	if (c == -1) {
7674f8b772fSflorian 		warn("asprintf");
7684f8b772fSflorian 		p = NULL;
7694f8b772fSflorian 	}
7704f8b772fSflorian 	return p;
7714f8b772fSflorian }
7724f8b772fSflorian 
7734f8b772fSflorian /*
7744f8b772fSflorian  * Protected component of json_fmt_signed().
7754f8b772fSflorian  */
7764f8b772fSflorian char *
json_fmt_protected_kid(const char * alg,const char * kid,const char * nce,const char * url)7774f8b772fSflorian json_fmt_protected_kid(const char *alg, const char *kid, const char *nce,
7784f8b772fSflorian     const char *url)
7794f8b772fSflorian {
7804f8b772fSflorian 	int	 c;
7814f8b772fSflorian 	char	*p;
7824f8b772fSflorian 
7834f8b772fSflorian 	c = asprintf(&p, "{"
7844f8b772fSflorian 	    "\"alg\": \"%s\", "
7857b00f4e9Sflorian 	    "\"kid\": \"%s\", "
7867b00f4e9Sflorian 	    "\"nonce\": \"%s\", "
7877b00f4e9Sflorian 	    "\"url\": \"%s\""
78855599e87Sderaadt 	    "}",
7894f8b772fSflorian 	    alg, kid, nce, url);
7907cd8f039Sjsing 	if (c == -1) {
791de579d12Sflorian 		warn("asprintf");
792de579d12Sflorian 		p = NULL;
793de579d12Sflorian 	}
79434335c11Sjsing 	return p;
795de579d12Sflorian }
796de579d12Sflorian 
797de579d12Sflorian /*
798de579d12Sflorian  * Signed message contents for the CA server.
799de579d12Sflorian  */
800de579d12Sflorian char *
json_fmt_signed(const char * protected,const char * payload,const char * digest)8017b00f4e9Sflorian json_fmt_signed(const char *protected, const char *payload, const char *digest)
802de579d12Sflorian {
803de579d12Sflorian 	int	 c;
804de579d12Sflorian 	char	*p;
805de579d12Sflorian 
806de579d12Sflorian 	c = asprintf(&p, "{"
807de579d12Sflorian 	    "\"protected\": \"%s\", "
808de579d12Sflorian 	    "\"payload\": \"%s\", "
809de579d12Sflorian 	    "\"signature\": \"%s\""
81055599e87Sderaadt 	    "}",
8117b00f4e9Sflorian 	    protected, payload, digest);
8127cd8f039Sjsing 	if (c == -1) {
813de579d12Sflorian 		warn("asprintf");
814de579d12Sflorian 		p = NULL;
815de579d12Sflorian 	}
81634335c11Sjsing 	return p;
817de579d12Sflorian }
818de579d12Sflorian 
819de579d12Sflorian /*
820de579d12Sflorian  * Produce thumbprint input.
821de579d12Sflorian  * This isn't technically a JSON string--it's the input we'll use for
822de579d12Sflorian  * hashing and digesting.
823de579d12Sflorian  * However, it's in the form of a JSON string, so do it here.
824de579d12Sflorian  */
825de579d12Sflorian char *
json_fmt_thumb_rsa(const char * exp,const char * mod)826de579d12Sflorian json_fmt_thumb_rsa(const char *exp, const char *mod)
827de579d12Sflorian {
828de579d12Sflorian 	int	 c;
829de579d12Sflorian 	char	*p;
830de579d12Sflorian 
831de579d12Sflorian 	/*NOTE: WHITESPACE IS IMPORTANT. */
832de579d12Sflorian 
83355599e87Sderaadt 	c = asprintf(&p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}",
834de579d12Sflorian 	    exp, mod);
8357cd8f039Sjsing 	if (c == -1) {
836de579d12Sflorian 		warn("asprintf");
837de579d12Sflorian 		p = NULL;
838de579d12Sflorian 	}
83934335c11Sjsing 	return p;
840de579d12Sflorian }
8414f8b772fSflorian 
8424f8b772fSflorian /*
8434f8b772fSflorian  * Produce thumbprint input.
8444f8b772fSflorian  * This isn't technically a JSON string--it's the input we'll use for
8454f8b772fSflorian  * hashing and digesting.
8464f8b772fSflorian  * However, it's in the form of a JSON string, so do it here.
8474f8b772fSflorian  */
8484f8b772fSflorian char *
json_fmt_thumb_ec(const char * x,const char * y)8494f8b772fSflorian json_fmt_thumb_ec(const char *x, const char *y)
8504f8b772fSflorian {
8514f8b772fSflorian 	int	 c;
8524f8b772fSflorian 	char	*p;
8534f8b772fSflorian 
8544f8b772fSflorian 	/*NOTE: WHITESPACE IS IMPORTANT. */
8554f8b772fSflorian 
8564f8b772fSflorian 	c = asprintf(&p, "{\"crv\":\"P-384\",\"kty\":\"EC\",\"x\":\"%s\","
8574f8b772fSflorian 	    "\"y\":\"%s\"}",
8584f8b772fSflorian 	    x, y);
8594f8b772fSflorian 	if (c == -1) {
8604f8b772fSflorian 		warn("asprintf");
8614f8b772fSflorian 		p = NULL;
8624f8b772fSflorian 	}
8634f8b772fSflorian 	return p;
8644f8b772fSflorian }
865