xref: /openbsd-src/usr.sbin/acme-client/netproc.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$Id: netproc.c,v 1.14 2017/11/27 01:58:52 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 <ctype.h>
20 #include <err.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 #include "http.h"
27 #include "extern.h"
28 #include "parse.h"
29 
30 #define	RETRY_DELAY 5
31 #define RETRY_MAX 10
32 
33 /*
34  * Buffer used when collecting the results of a CURL transfer.
35  */
36 struct	buf {
37 	char	*buf; /* binary buffer */
38 	size_t	 sz; /* length of buffer */
39 };
40 
41 /*
42  * Used for CURL communications.
43  */
44 struct	conn {
45 	const char	  *na; /* nonce authority */
46 	int		   fd; /* acctproc handle */
47 	int		   dfd; /* dnsproc handle */
48 	struct buf	   buf; /* transfer buffer */
49 };
50 
51 /*
52  * If something goes wrong (or we're tracing output), we dump the
53  * current transfer's data as a debug message.
54  * Make sure that print all non-printable characters as question marks
55  * so that we don't spam the console.
56  * Also, consolidate white-space.
57  * This of course will ruin string literals, but the intent here is just
58  * to show the message, not to replicate it.
59  */
60 static void
61 buf_dump(const struct buf *buf)
62 {
63 	size_t	 i;
64 	int	 j;
65 	char	*nbuf;
66 
67 	if (buf->sz == 0)
68 		return;
69 	if ((nbuf = malloc(buf->sz)) == NULL)
70 		err(EXIT_FAILURE, "malloc");
71 
72 	for (j = 0, i = 0; i < buf->sz; i++)
73 		if (isspace((int)buf->buf[i])) {
74 			nbuf[j++] = ' ';
75 			while (isspace((int)buf->buf[i]))
76 				i++;
77 			i--;
78 		} else
79 			nbuf[j++] = isprint((int)buf->buf[i]) ?
80 			    buf->buf[i] : '?';
81 	dodbg("transfer buffer: [%.*s] (%zu bytes)", j, nbuf, buf->sz);
82 	free(nbuf);
83 }
84 
85 /*
86  * Extract the domain and port from a URL.
87  * The url must be formatted as schema://address[/stuff].
88  * This returns NULL on failure.
89  */
90 static char *
91 url2host(const char *host, short *port, char **path)
92 {
93 	char	*url, *ep;
94 
95 	/* We only understand HTTP and HTTPS. */
96 
97 	if (strncmp(host, "https://", 8) == 0) {
98 		*port = 443;
99 		if ((url = strdup(host + 8)) == NULL) {
100 			warn("strdup");
101 			return NULL;
102 		}
103 	} else if (strncmp(host, "http://", 7) == 0) {
104 		*port = 80;
105 		if ((url = strdup(host + 7)) == NULL) {
106 			warn("strdup");
107 			return NULL;
108 		}
109 	} else {
110 		warnx("%s: unknown schema", host);
111 		return NULL;
112 	}
113 
114 	/* Terminate path part. */
115 
116 	if ((ep = strchr(url, '/')) != NULL) {
117 		*path = strdup(ep);
118 		*ep = '\0';
119 	} else
120 		*path = strdup("");
121 
122 	if (*path == NULL) {
123 		warn("strdup");
124 		free(url);
125 		return NULL;
126 	}
127 
128 	return url;
129 }
130 
131 /*
132  * Contact dnsproc and resolve a host.
133  * Place the answers in "v" and return the number of answers, which can
134  * be at most MAX_SERVERS_DNS.
135  * Return <0 on failure.
136  */
137 static ssize_t
138 urlresolve(int fd, const char *host, struct source *v)
139 {
140 	char		*addr;
141 	size_t		 i, sz;
142 	long		 lval;
143 
144 	if (writeop(fd, COMM_DNS, DNS_LOOKUP) <= 0)
145 		return -1;
146 	else if (writestr(fd, COMM_DNSQ, host) <= 0)
147 		return -1;
148 	else if ((lval = readop(fd, COMM_DNSLEN)) < 0)
149 		return -1;
150 
151 	sz = lval;
152 	assert(sz <= MAX_SERVERS_DNS);
153 
154 	for (i = 0; i < sz; i++) {
155 		memset(&v[i], 0, sizeof(struct source));
156 		if ((lval = readop(fd, COMM_DNSF)) < 0)
157 			goto err;
158 		else if (lval != 4 && lval != 6)
159 			goto err;
160 		else if ((addr = readstr(fd, COMM_DNSA)) == NULL)
161 			goto err;
162 		v[i].family = lval;
163 		v[i].ip = addr;
164 	}
165 
166 	return sz;
167 err:
168 	for (i = 0; i < sz; i++)
169 		free(v[i].ip);
170 	return -1;
171 }
172 
173 /*
174  * Send a "regular" HTTP GET message to "addr" and stuff the response
175  * into the connection buffer.
176  * Return the HTTP error code or <0 on failure.
177  */
178 static long
179 nreq(struct conn *c, const char *addr)
180 {
181 	struct httpget	*g;
182 	struct source	 src[MAX_SERVERS_DNS];
183 	char		*host, *path;
184 	short		 port;
185 	size_t		 srcsz;
186 	ssize_t		 ssz;
187 	long		 code;
188 
189 	if ((host = url2host(addr, &port, &path)) == NULL)
190 		return -1;
191 
192 	if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
193 		free(host);
194 		free(path);
195 		return -1;
196 	}
197 	srcsz = ssz;
198 
199 	g = http_get(src, srcsz, host, port, path, NULL, 0);
200 	free(host);
201 	free(path);
202 	if (g == NULL)
203 		return -1;
204 
205 	code = g->code;
206 
207 	/* Copy the body part into our buffer. */
208 
209 	free(c->buf.buf);
210 	c->buf.sz = g->bodypartsz;
211 	c->buf.buf = malloc(c->buf.sz);
212 	memcpy(c->buf.buf, g->bodypart, c->buf.sz);
213 	http_get_free(g);
214 	if (c->buf.buf == NULL) {
215 		warn("malloc");
216 		return -1;
217 	}
218 	return code;
219 }
220 
221 /*
222  * Create and send a signed communication to the ACME server.
223  * Stuff the response into the communication buffer.
224  * Return <0 on failure on the HTTP error code otherwise.
225  */
226 static long
227 sreq(struct conn *c, const char *addr, const char *req)
228 {
229 	struct httpget	*g;
230 	struct source	 src[MAX_SERVERS_DNS];
231 	char		*host, *path, *nonce, *reqsn;
232 	short		 port;
233 	struct httphead	*h;
234 	ssize_t		 ssz;
235 	long		 code;
236 
237 	if ((host = url2host(c->na, &port, &path)) == NULL)
238 		return -1;
239 
240 	if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
241 		free(host);
242 		free(path);
243 		return -1;
244 	}
245 
246 	g = http_get(src, (size_t)ssz, host, port, path, NULL, 0);
247 	free(host);
248 	free(path);
249 	if (g == NULL)
250 		return -1;
251 
252 	h = http_head_get("Replay-Nonce", g->head, g->headsz);
253 	if (h == NULL) {
254 		warnx("%s: no replay nonce", c->na);
255 		http_get_free(g);
256 		return -1;
257 	} else if ((nonce = strdup(h->val)) == NULL) {
258 		warn("strdup");
259 		http_get_free(g);
260 		return -1;
261 	}
262 	http_get_free(g);
263 
264 	/*
265 	 * Send the nonce and request payload to the acctproc.
266 	 * This will create the proper JSON object we need.
267 	 */
268 
269 	if (writeop(c->fd, COMM_ACCT, ACCT_SIGN) <= 0) {
270 		free(nonce);
271 		return -1;
272 	} else if (writestr(c->fd, COMM_PAY, req) <= 0) {
273 		free(nonce);
274 		return -1;
275 	} else if (writestr(c->fd, COMM_NONCE, nonce) <= 0) {
276 		free(nonce);
277 		return -1;
278 	}
279 	free(nonce);
280 
281 	/* Now read back the signed payload. */
282 
283 	if ((reqsn = readstr(c->fd, COMM_REQ)) == NULL)
284 		return -1;
285 
286 	/* Now send the signed payload to the CA. */
287 
288 	if ((host = url2host(addr, &port, &path)) == NULL) {
289 		free(reqsn);
290 		return -1;
291 	} else if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
292 		free(host);
293 		free(path);
294 		free(reqsn);
295 		return -1;
296 	}
297 
298 	g = http_get(src, (size_t)ssz, host, port, path, reqsn, strlen(reqsn));
299 
300 	free(host);
301 	free(path);
302 	free(reqsn);
303 	if (g == NULL)
304 		return -1;
305 
306 	/* Stuff response into parse buffer. */
307 
308 	code = g->code;
309 
310 	free(c->buf.buf);
311 	c->buf.sz = g->bodypartsz;
312 	c->buf.buf = malloc(c->buf.sz);
313 	memcpy(c->buf.buf, g->bodypart, c->buf.sz);
314 	http_get_free(g);
315 	if (c->buf.buf == NULL) {
316 		warn("malloc");
317 		return -1;
318 	}
319 	return code;
320 }
321 
322 /*
323  * Send to the CA that we want to authorise a new account.
324  * This only happens once for a new account key.
325  * Returns non-zero on success.
326  */
327 static int
328 donewreg(struct conn *c, const struct capaths *p)
329 {
330 	int		 rc = 0;
331 	char		*req;
332 	long		 lc;
333 
334 	dodbg("%s: new-reg", p->newreg);
335 
336 	if ((req = json_fmt_newreg(p->agreement)) == NULL)
337 		warnx("json_fmt_newreg");
338 	else if ((lc = sreq(c, p->newreg, req)) < 0)
339 		warnx("%s: bad comm", p->newreg);
340 	else if (lc != 200 && lc != 201)
341 		warnx("%s: bad HTTP: %ld", p->newreg, lc);
342 	else if (c->buf.buf == NULL || c->buf.sz == 0)
343 		warnx("%s: empty response", p->newreg);
344 	else
345 		rc = 1;
346 
347 	if (rc == 0 || verbose > 1)
348 		buf_dump(&c->buf);
349 	free(req);
350 	return rc;
351 }
352 
353 /*
354  * Request a challenge for the given domain name.
355  * This must happen for each name "alt".
356  * On non-zero exit, fills in "chng" with the challenge.
357  */
358 static int
359 dochngreq(struct conn *c, const char *alt, struct chng *chng,
360     const struct capaths *p)
361 {
362 	int		 rc = 0;
363 	char		*req;
364 	long		 lc;
365 	struct jsmnn	*j = NULL;
366 
367 	dodbg("%s: req-auth: %s", p->newauthz, alt);
368 
369 	if ((req = json_fmt_newauthz(alt)) == NULL)
370 		warnx("json_fmt_newauthz");
371 	else if ((lc = sreq(c, p->newauthz, req)) < 0)
372 		warnx("%s: bad comm", p->newauthz);
373 	else if (lc != 200 && lc != 201)
374 		warnx("%s: bad HTTP: %ld", p->newauthz, lc);
375 	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
376 		warnx("%s: bad JSON object", p->newauthz);
377 	else if (!json_parse_challenge(j, chng))
378 		warnx("%s: bad challenge", p->newauthz);
379 	else
380 		rc = 1;
381 
382 	if (rc == 0 || verbose > 1)
383 		buf_dump(&c->buf);
384 	json_free(j);
385 	free(req);
386 	return rc;
387 }
388 
389 /*
390  * Note to the CA that a challenge response is in place.
391  */
392 static int
393 dochngresp(struct conn *c, const struct chng *chng, const char *th)
394 {
395 	int	 rc = 0;
396 	long	 lc;
397 	char	*req;
398 
399 	dodbg("%s: challenge", chng->uri);
400 
401 	if ((req = json_fmt_challenge(chng->token, th)) == NULL)
402 		warnx("json_fmt_challenge");
403 	else if ((lc = sreq(c, chng->uri, req)) < 0)
404 		warnx("%s: bad comm", chng->uri);
405 	else if (lc != 200 && lc != 201 && lc != 202)
406 		warnx("%s: bad HTTP: %ld", chng->uri, lc);
407 	else
408 		rc = 1;
409 
410 	if (rc == 0 || verbose > 1)
411 		buf_dump(&c->buf);
412 	free(req);
413 	return rc;
414 }
415 
416 /*
417  * Check with the CA whether a challenge has been processed.
418  * Note: we'll only do this a limited number of times, and pause for a
419  * time between checks, but this happens in the caller.
420  */
421 static int
422 dochngcheck(struct conn *c, struct chng *chng)
423 {
424 	int		 cc;
425 	long		 lc;
426 	struct jsmnn	*j;
427 
428 	dodbg("%s: status", chng->uri);
429 
430 	if ((lc = nreq(c, chng->uri)) < 0) {
431 		warnx("%s: bad comm", chng->uri);
432 		return 0;
433 	} else if (lc != 200 && lc != 201 && lc != 202) {
434 		warnx("%s: bad HTTP: %ld", chng->uri, lc);
435 		buf_dump(&c->buf);
436 		return 0;
437 	} else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL) {
438 		warnx("%s: bad JSON object", chng->uri);
439 		buf_dump(&c->buf);
440 		return 0;
441 	} else if ((cc = json_parse_response(j)) == -1) {
442 		warnx("%s: bad response", chng->uri);
443 		buf_dump(&c->buf);
444 		json_free(j);
445 		return 0;
446 	} else if (cc > 0)
447 		chng->status = 1;
448 
449 	json_free(j);
450 	return 1;
451 }
452 
453 static int
454 dorevoke(struct conn *c, const char *addr, const char *cert)
455 {
456 	char		*req;
457 	int		 rc = 0;
458 	long		 lc = 0;
459 
460 	dodbg("%s: revocation", addr);
461 
462 	if ((req = json_fmt_revokecert(cert)) == NULL)
463 		warnx("json_fmt_revokecert");
464 	else if ((lc = sreq(c, addr, req)) < 0)
465 		warnx("%s: bad comm", addr);
466 	else if (lc != 200 && lc != 201 && lc != 409)
467 		warnx("%s: bad HTTP: %ld", addr, lc);
468 	else
469 		rc = 1;
470 
471 	if (lc == 409)
472 		warnx("%s: already revoked", addr);
473 
474 	if (rc == 0 || verbose > 1)
475 		buf_dump(&c->buf);
476 	free(req);
477 	return rc;
478 }
479 
480 /*
481  * Submit our certificate to the CA.
482  * This, upon success, will return the signed CA.
483  */
484 static int
485 docert(struct conn *c, const char *addr, const char *cert)
486 {
487 	char	*req;
488 	int	 rc = 0;
489 	long	 lc;
490 
491 	dodbg("%s: certificate", addr);
492 
493 	if ((req = json_fmt_newcert(cert)) == NULL)
494 		warnx("json_fmt_newcert");
495 	else if ((lc = sreq(c, addr, req)) < 0)
496 		warnx("%s: bad comm", addr);
497 	else if (lc != 200 && lc != 201)
498 		warnx("%s: bad HTTP: %ld", addr, lc);
499 	else if (c->buf.sz == 0 || c->buf.buf == NULL)
500 		warnx("%s: empty response", addr);
501 	else
502 		rc = 1;
503 
504 	if (rc == 0 || verbose > 1)
505 		buf_dump(&c->buf);
506 	free(req);
507 	return rc;
508 }
509 
510 /*
511  * Look up directories from the certificate authority.
512  */
513 static int
514 dodirs(struct conn *c, const char *addr, struct capaths *paths)
515 {
516 	struct jsmnn	*j = NULL;
517 	long		 lc;
518 	int		 rc = 0;
519 
520 	dodbg("%s: directories", addr);
521 
522 	if ((lc = nreq(c, addr)) < 0)
523 		warnx("%s: bad comm", addr);
524 	else if (lc != 200 && lc != 201)
525 		warnx("%s: bad HTTP: %ld", addr, lc);
526 	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
527 		warnx("json_parse");
528 	else if (!json_parse_capaths(j, paths))
529 		warnx("%s: bad CA paths", addr);
530 	else
531 		rc = 1;
532 
533 	if (rc == 0 || verbose > 1)
534 		buf_dump(&c->buf);
535 	json_free(j);
536 	return rc;
537 }
538 
539 /*
540  * Request the full chain certificate.
541  */
542 static int
543 dofullchain(struct conn *c, const char *addr)
544 {
545 	int	 rc = 0;
546 	long	 lc;
547 
548 	dodbg("%s: full chain", addr);
549 
550 	if ((lc = nreq(c, addr)) < 0)
551 		warnx("%s: bad comm", addr);
552 	else if (lc != 200 && lc != 201)
553 		warnx("%s: bad HTTP: %ld", addr, lc);
554 	else
555 		rc = 1;
556 
557 	if (rc == 0 || verbose > 1)
558 		buf_dump(&c->buf);
559 	return rc;
560 }
561 
562 /*
563  * Here we communicate with the ACME server.
564  * For this, we'll need the certificate we want to upload and our
565  * account key information.
566  */
567 int
568 netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
569     int newacct, int revocate, struct authority_c *authority,
570     const char *const *alts,size_t altsz)
571 {
572 	int		 rc = 0;
573 	size_t		 i;
574 	char		*cert = NULL, *thumb = NULL, *url = NULL;
575 	struct conn	 c;
576 	struct capaths	 paths;
577 	struct chng	*chngs = NULL;
578 	long		 lval;
579 
580 	memset(&paths, 0, sizeof(struct capaths));
581 	memset(&c, 0, sizeof(struct conn));
582 
583 	if (pledge("stdio inet rpath", NULL) == -1) {
584 		warn("pledge");
585 		goto out;
586 	}
587 
588 	if (http_init() == -1) {
589 		warn("http_init");
590 		goto out;
591 	}
592 
593 	if (pledge("stdio inet", NULL) == -1) {
594 		warn("pledge");
595 		goto out;
596 	}
597 
598 	/*
599 	 * Wait until the acctproc, keyproc, and revokeproc have started
600 	 * up and are ready to serve us data.
601 	 * There's no point in running if these don't work.
602 	 * Then check whether revokeproc indicates that the certificate
603 	 * on file (if any) can be updated.
604 	 */
605 
606 	if ((lval = readop(afd, COMM_ACCT_STAT)) == 0) {
607 		rc = 1;
608 		goto out;
609 	} else if (lval != ACCT_READY) {
610 		warnx("unknown operation from acctproc");
611 		goto out;
612 	}
613 
614 	if ((lval = readop(kfd, COMM_KEY_STAT)) == 0) {
615 		rc = 1;
616 		goto out;
617 	} else if (lval != KEY_READY) {
618 		warnx("unknown operation from keyproc");
619 		goto out;
620 	}
621 
622 	if ((lval = readop(rfd, COMM_REVOKE_RESP)) == 0) {
623 		rc = 1;
624 		goto out;
625 	} else if (lval != REVOKE_EXP && lval != REVOKE_OK) {
626 		warnx("unknown operation from revokeproc");
627 		goto out;
628 	}
629 
630 	/* If our certificate is up-to-date, return now. */
631 
632 	if (lval == REVOKE_OK) {
633 		rc = 1;
634 		goto out;
635 	}
636 
637 	/* Allocate main state. */
638 
639 	chngs = calloc(altsz, sizeof(struct chng));
640 	if (chngs == NULL) {
641 		warn("calloc");
642 		goto out;
643 	}
644 
645 	c.dfd = dfd;
646 	c.fd = afd;
647 	c.na = authority->api;
648 
649 	/*
650 	 * Look up the domain of the ACME server.
651 	 * We'll use this ourselves instead of having libcurl do the DNS
652 	 * resolution itself.
653 	 */
654 	if (!dodirs(&c, c.na, &paths))
655 		goto out;
656 
657 	/*
658 	 * If we're meant to revoke, then wait for revokeproc to send us
659 	 * the certificate (if it's found at all).
660 	 * Following that, submit the request to the CA then notify the
661 	 * certproc, which will in turn notify the fileproc.
662 	 */
663 
664 	if (revocate) {
665 		if ((cert = readstr(rfd, COMM_CSR)) == NULL)
666 			goto out;
667 		if (!dorevoke(&c, paths.revokecert, cert))
668 			goto out;
669 		else if (writeop(cfd, COMM_CSR_OP, CERT_REVOKE) > 0)
670 			rc = 1;
671 		goto out;
672 	}
673 
674 	/* If new, register with the CA server. */
675 
676 	if (newacct && ! donewreg(&c, &paths))
677 		goto out;
678 
679 	/* Pre-authorise all domains with CA server. */
680 
681 	for (i = 0; i < altsz; i++)
682 		if (!dochngreq(&c, alts[i], &chngs[i], &paths))
683 			goto out;
684 
685 	/*
686 	 * We now have our challenges.
687 	 * We need to ask the acctproc for the thumbprint.
688 	 * We'll combine this to the challenge to create our response,
689 	 * which will be orchestrated by the chngproc.
690 	 */
691 
692 	if (writeop(afd, COMM_ACCT, ACCT_THUMBPRINT) <= 0)
693 		goto out;
694 	else if ((thumb = readstr(afd, COMM_THUMB)) == NULL)
695 		goto out;
696 
697 	/* We'll now ask chngproc to build the challenge. */
698 
699 	for (i = 0; i < altsz; i++) {
700 		if (writeop(Cfd, COMM_CHNG_OP, CHNG_SYN) <= 0)
701 			goto out;
702 		else if (writestr(Cfd, COMM_THUMB, thumb) <= 0)
703 			goto out;
704 		else if (writestr(Cfd, COMM_TOK, chngs[i].token) <= 0)
705 			goto out;
706 
707 		/* Read that the challenge has been made. */
708 
709 		if (readop(Cfd, COMM_CHNG_ACK) != CHNG_ACK)
710 			goto out;
711 
712 		/* Write to the CA that it's ready. */
713 
714 		if (!dochngresp(&c, &chngs[i], thumb))
715 			goto out;
716 	}
717 
718 	/*
719 	 * We now wait on the ACME server for each domain.
720 	 * Connect to the server (assume it's the same server) once
721 	 * every five seconds.
722 	 */
723 
724 	for (i = 0; i < altsz; i++) {
725 		if (chngs[i].status == 1)
726 			continue;
727 
728 		if (chngs[i].retry++ >= RETRY_MAX) {
729 			warnx("%s: too many tries", chngs[i].uri);
730 			goto out;
731 		}
732 
733 		/* Sleep before every attempt. */
734 		sleep(RETRY_DELAY);
735 		if (!dochngcheck(&c, &chngs[i]))
736 			goto out;
737 	}
738 
739 	/*
740 	 * Write our acknowledgement that the challenges are over.
741 	 * The challenge process will remove all of the files.
742 	 */
743 
744 	if (writeop(Cfd, COMM_CHNG_OP, CHNG_STOP) <= 0)
745 		goto out;
746 
747 	/* Wait to receive the certificate itself. */
748 
749 	if ((cert = readstr(kfd, COMM_CERT)) == NULL)
750 		goto out;
751 
752 	/*
753 	 * Otherwise, submit the CA for signing, download the signed
754 	 * copy, and ship that into the certificate process for copying.
755 	 */
756 
757 	if (!docert(&c, paths.newcert, cert))
758 		goto out;
759 	else if (writeop(cfd, COMM_CSR_OP, CERT_UPDATE) <= 0)
760 		goto out;
761 	else if (writebuf(cfd, COMM_CSR, c.buf.buf, c.buf.sz) <= 0)
762 		goto out;
763 
764 	/*
765 	 * Read back the issuer from the certproc.
766 	 * Then contact the issuer to get the certificate chain.
767 	 * Write this chain directly back to the certproc.
768 	 */
769 
770 	if ((url = readstr(cfd, COMM_ISSUER)) == NULL)
771 		goto out;
772 	else if (!dofullchain(&c, url))
773 		goto out;
774 	else if (writebuf(cfd, COMM_CHAIN, c.buf.buf, c.buf.sz) <= 0)
775 		goto out;
776 
777 	rc = 1;
778 out:
779 	close(cfd);
780 	close(kfd);
781 	close(afd);
782 	close(Cfd);
783 	close(dfd);
784 	close(rfd);
785 	free(cert);
786 	free(url);
787 	free(thumb);
788 	free(c.buf.buf);
789 	if (chngs != NULL)
790 		for (i = 0; i < altsz; i++)
791 			json_free_challenge(&chngs[i]);
792 	free(chngs);
793 	json_free_capaths(&paths);
794 	return rc;
795 }
796