Bug Summary

File:src/usr.sbin/acme-client/json.c
Warning:line 508, column 8
Array access (via field 'auths') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name json.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/acme-client/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/acme-client -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/acme-client/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/acme-client/json.c
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)((parse->cur < parse->max) ? (void)0 : __assert2("/usr/src/usr.sbin/acme-client/json.c"
, 81, __func__, "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((void*)0))
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((void*)0))
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((void*)0))
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((void*)0))
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((void*)0);
191
192 p = calloc(1, sizeof(struct parse));
193 if (p == NULL((void*)0))
194 return NULL((void*)0);
195
196 p->max = sz;
197 p->nodes = calloc(p->max, sizeof(struct jsmnn));
198 if (p->nodes == NULL((void*)0)) {
199 free(p);
200 return NULL((void*)0);
201 }
202
203 if (build(p, &first, t, js, sz) < 0) {
204 jsmnparse_free(p);
205 first = NULL((void*)0);
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((void*)0))
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((void*)0) : 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((void*)0) : 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((void*)0);
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((void*)0);
263 if (n->d.obj[i].rhs->type != JSMN_ARRAY)
264 return NULL((void*)0);
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((void*)0);
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((void*)0);
290 if (n->d.obj[i].rhs->type != JSMN_OBJECT)
291 return NULL((void*)0);
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((void*)0);
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((void*)0);
318 if (n->d.obj[i].rhs->type != JSMN_STRING &&
319 n->d.obj[i].rhs->type != JSMN_PRIMITIVE)
320 return NULL((void*)0);
321
322 cp = strdup(n->d.obj[i].rhs->d.str);
323 if (cp == NULL((void*)0))
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((void*)0);
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((void*)0))
351 return CHNG_INVALID;
352 if ((resp = json_getstr(n, "status")) == NULL((void*)0))
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((void*)0))
382 return 0;
383
384 array = json_getarray(n, "challenges");
385 if (array == NULL((void*)0))
386 return 0;
387
388 for (i = 0; i < array->fields; i++) {
389 obj = json_getarrayobj(array->d.array[i]);
390 if (obj == NULL((void*)0))
391 continue;
392 type = json_getstr(obj, "type");
393 if (type == NULL((void*)0))
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((void*)0) && p->token != NULL((void*)0);
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((void*)0))
418 return ORDER_INVALID;
419
420 if ((status = json_getstr(n, "status")) == NULL((void*)0))
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
0.1
'n' is not equal to NULL
== NULL((void*)0))
1
Taking false branch
451 return 0;
452
453 if ((finalize = json_getstr(n, "finalize")) == NULL((void*)0)) {
2
Assuming the condition is false
3
Taking false branch
454 warnx("no finalize field in order response");
455 return 0;
456 }
457
458 if ((order->finalize = strdup(finalize)) == NULL((void*)0))
4
Assuming the condition is false
5
Taking false branch
459 goto err;
460
461 if ((array = json_getarray(n, "authorizations")) == NULL((void*)0))
6
Taking false branch
462 goto err;
463
464 if (array->fields > 0) {
7
Assuming field 'fields' is > 0
8
Taking true branch
465 order->auths = calloc(array->fields, sizeof(*order->auths));
9
Value assigned to field 'auths'
466 if (order->auths == NULL((void*)0)) {
10
Assuming field 'auths' is equal to NULL
11
Taking true branch
467 warn("malloc");
468 goto err;
12
Control jumps to line 484
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((void*)0))
476 continue;
477 if ((order->auths[i] = strdup(str)) == NULL((void*)0)) {
478 warn("strdup");
479 goto err;
480 }
481 }
482 return 1;
483err:
484 json_free_order(order);
13
Calling 'json_free_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((void*)0)) {
494 if ((order->certificate = strdup(certificate)) == NULL((void*)0))
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((void*)0);
507 for(i = 0; i < order->authsz; i++)
14
Assuming 'i' is < field 'authsz'
15
Loop condition is true. Entering loop body
508 free(order->auths[i]);
16
Array access (via field 'auths') results in a null pointer dereference
509 free(order->auths);
510
511 order->finalize = NULL((void*)0);
512 order->auths = NULL((void*)0);
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((void*)0))
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((void*)0) && p->newnonce != NULL((void*)0) &&
532 p->neworder != NULL((void*)0) && p->revokecert != NULL((void*)0);
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((void*)0)) {
566 warn("calloc");
567 return NULL((void*)0);
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((void*)0)) {
577 warn("calloc");
578 free(tok);
579 return NULL((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
625
626 if (contact != NULL((void*)0)) {
627 c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
628 if (c == -1) {
629 warn("asprintf");
630 return NULL((void*)0);
631 }
632 }
633
634 c = asprintf(&p, "{"
635 "%s"
636 "\"termsOfServiceAgreed\": true"
637 "}", cnt == NULL((void*)0) ? "" : cnt);
638 free(cnt);
639 if (c == -1) {
640 warn("asprintf");
641 p = NULL((void*)0);
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((void*)0))
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((void*)0);
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((void*)0);
677 }
678 return p;
679err:
680 free(p);
681 return NULL((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
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((void*)0);
862 }
863 return p;
864}