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