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