xref: /openbsd/usr.sbin/acme-client/netproc.c (revision 274d7c50)
1 /*	$Id: netproc.c,v 1.25 2019/08/11 19:44:25 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 #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	  *newnonce; /* nonce authority */
47 	char		  *kid; /* kid when account exists */
48 	int		   fd; /* acctproc handle */
49 	int		   dfd; /* dnsproc handle */
50 	struct buf	   buf; /* http body buffer */
51 };
52 
53 /*
54  * If something goes wrong (or we're tracing output), we dump the
55  * current transfer's data as a debug message.
56  * Make sure that print all non-printable characters as question marks
57  * so that we don't spam the console.
58  * Also, consolidate white-space.
59  * This of course will ruin string literals, but the intent here is just
60  * to show the message, not to replicate it.
61  */
62 static void
63 buf_dump(const struct buf *buf)
64 {
65 	size_t	 i;
66 	int	 j;
67 	char	*nbuf;
68 
69 	if (buf->sz == 0)
70 		return;
71 	if ((nbuf = malloc(buf->sz)) == NULL)
72 		err(EXIT_FAILURE, "malloc");
73 
74 	for (j = 0, i = 0; i < buf->sz; i++)
75 		if (isspace((int)buf->buf[i])) {
76 			nbuf[j++] = ' ';
77 			while (isspace((int)buf->buf[i]))
78 				i++;
79 			i--;
80 		} else
81 			nbuf[j++] = isprint((int)buf->buf[i]) ?
82 			    buf->buf[i] : '?';
83 	dodbg("transfer buffer: [%.*s] (%zu bytes)", j, nbuf, buf->sz);
84 	free(nbuf);
85 }
86 
87 /*
88  * Extract the domain and port from a URL.
89  * The url must be formatted as schema://address[/stuff].
90  * This returns NULL on failure.
91  */
92 static char *
93 url2host(const char *host, short *port, char **path)
94 {
95 	char	*url, *ep;
96 
97 	/* We only understand HTTP and HTTPS. */
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 	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 	struct httphead *st;
184 	char		*host, *path;
185 	short		 port;
186 	size_t		 srcsz;
187 	ssize_t		 ssz;
188 	long		 code;
189 	int		 redirects = 0;
190 
191 	if ((host = url2host(addr, &port, &path)) == NULL)
192 		return -1;
193 
194 again:
195 	if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
196 		free(host);
197 		free(path);
198 		return -1;
199 	}
200 	srcsz = ssz;
201 
202 	g = http_get(src, srcsz, host, port, path, 0, NULL, 0);
203 	free(host);
204 	free(path);
205 	if (g == NULL)
206 		return -1;
207 
208 	switch (g->code) {
209 	case 301:
210 	case 302:
211 	case 303:
212 	case 307:
213 	case 308:
214 		redirects++;
215 		if (redirects > 3) {
216 			warnx("too many redirects");
217 			http_get_free(g);
218 			return -1;
219 		}
220 
221 		if ((st = http_head_get("Location", g->head, g->headsz)) ==
222 		    NULL) {
223 			warnx("redirect without location header");
224 			return -1;
225 		}
226 
227 		host = url2host(st->val, &port, &path);
228 		http_get_free(g);
229 		if (host == NULL)
230 			return -1;
231 		goto again;
232 		break;
233 	default:
234 		code = g->code;
235 		break;
236 	}
237 
238 	/* Copy the body part into our buffer. */
239 	free(c->buf.buf);
240 	c->buf.sz = g->bodypartsz;
241 	c->buf.buf = malloc(c->buf.sz);
242 	if (c->buf.buf == NULL) {
243 		warn("malloc");
244 		code = -1;
245 	} else
246 		memcpy(c->buf.buf, g->bodypart, c->buf.sz);
247 	http_get_free(g);
248 	return code;
249 }
250 
251 /*
252  * Create and send a signed communication to the ACME server.
253  * Stuff the response into the communication buffer.
254  * Return <0 on failure on the HTTP error code otherwise.
255  */
256 static long
257 sreq(struct conn *c, const char *addr, int kid, const char *req, char **loc)
258 {
259 	struct httpget	*g;
260 	struct source	 src[MAX_SERVERS_DNS];
261 	char		*host, *path, *nonce, *reqsn;
262 	short		 port;
263 	struct httphead	*h;
264 	ssize_t		 ssz;
265 	long		 code;
266 
267 	if ((host = url2host(c->newnonce, &port, &path)) == NULL)
268 		return -1;
269 
270 	if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
271 		free(host);
272 		free(path);
273 		return -1;
274 	}
275 
276 	g = http_get(src, (size_t)ssz, host, port, path, 1, NULL, 0);
277 	free(host);
278 	free(path);
279 	if (g == NULL)
280 		return -1;
281 
282 	h = http_head_get("Replay-Nonce", g->head, g->headsz);
283 	if (h == NULL) {
284 		warnx("%s: no replay nonce", c->newnonce);
285 		http_get_free(g);
286 		return -1;
287 	} else if ((nonce = strdup(h->val)) == NULL) {
288 		warn("strdup");
289 		http_get_free(g);
290 		return -1;
291 	}
292 	http_get_free(g);
293 
294 	/*
295 	 * Send the url, nonce and request payload to the acctproc.
296 	 * This will create the proper JSON object we need.
297 	 */
298 	if (writeop(c->fd, COMM_ACCT, kid ? ACCT_KID_SIGN : ACCT_SIGN) <= 0) {
299 		free(nonce);
300 		return -1;
301 	} else if (writestr(c->fd, COMM_PAY, req) <= 0) {
302 		free(nonce);
303 		return -1;
304 	} else if (writestr(c->fd, COMM_NONCE, nonce) <= 0) {
305 		free(nonce);
306 		return -1;
307 	} else if (writestr(c->fd, COMM_URL, addr) <= 0) {
308 		free(nonce);
309 		return -1;
310 	}
311 	free(nonce);
312 
313 	if (kid && writestr(c->fd, COMM_KID, c->kid) <= 0)
314 		return -1;
315 
316 	/* Now read back the signed payload. */
317 	if ((reqsn = readstr(c->fd, COMM_REQ)) == NULL)
318 		return -1;
319 
320 	/* Now send the signed payload to the CA. */
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, 0, reqsn,
332 	    strlen(reqsn));
333 
334 	free(host);
335 	free(path);
336 	free(reqsn);
337 	if (g == NULL)
338 		return -1;
339 
340 	/* Stuff response into parse buffer. */
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 
352 	if (loc != NULL) {
353 		free(*loc);
354 		*loc = NULL;
355 		h = http_head_get("Location", g->head, g->headsz);
356 		/* error checking done by caller */
357 		if (h != NULL)
358 			*loc = strdup(h->val);
359 	}
360 
361 	http_get_free(g);
362 	return code;
363 }
364 
365 /*
366  * Send to the CA that we want to authorise a new account.
367  * This only happens once for a new account key.
368  * Returns non-zero on success.
369  */
370 static int
371 donewacc(struct conn *c, const struct capaths *p)
372 {
373 	int		 rc = 0;
374 	char		*req;
375 	long		 lc;
376 
377 	if ((req = json_fmt_newacc()) == NULL)
378 		warnx("json_fmt_newacc");
379 	else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0)
380 		warnx("%s: bad comm", p->newaccount);
381 	else if (lc != 200 && lc != 201)
382 		warnx("%s: bad HTTP: %ld", p->newaccount, lc);
383 	else if (c->buf.buf == NULL || c->buf.sz == 0)
384 		warnx("%s: empty response", p->newaccount);
385 	else
386 		rc = 1;
387 
388 	if (rc == 0 || verbose > 1)
389 		buf_dump(&c->buf);
390 	free(req);
391 	return rc;
392 }
393 
394 /*
395  * Check if our account already exists, if not create it.
396  * Populates conn->kid.
397  * Returns non-zero on success.
398  */
399 static int
400 dochkacc(struct conn *c, const struct capaths *p)
401 {
402 	int		 rc = 0;
403 	char		*req;
404 	long		 lc;
405 
406 	if ((req = json_fmt_chkacc()) == NULL)
407 		warnx("json_fmt_chkacc");
408 	else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0)
409 		warnx("%s: bad comm", p->newaccount);
410 	else if (lc != 200 && lc != 400)
411 		warnx("%s: bad HTTP: %ld", p->newaccount, lc);
412 	else if (c->buf.buf == NULL || c->buf.sz == 0)
413 		warnx("%s: empty response", p->newaccount);
414 	else if (lc == 400)
415 		rc = donewacc(c, p);
416 	else
417 		rc = 1;
418 
419 	if (c->kid == NULL)
420 		rc = 0;
421 
422 	if (rc == 0 || verbose > 1)
423 		buf_dump(&c->buf);
424 	free(req);
425 	return rc;
426 }
427 
428 /*
429  * Submit a new order for a certificate.
430  */
431 static int
432 doneworder(struct conn *c, const char *const *alts, size_t altsz,
433     struct order *order, const struct capaths *p)
434 {
435 	struct jsmnn	*j = NULL;
436 	int		 rc = 0;
437 	char		*req;
438 	long		 lc;
439 
440 	if ((req = json_fmt_neworder(alts, altsz)) == NULL)
441 		warnx("json_fmt_neworder");
442 	else if ((lc = sreq(c, p->neworder, 1, req, &order->uri)) < 0)
443 		warnx("%s: bad comm", p->neworder);
444 	else if (lc != 201)
445 		warnx("%s: bad HTTP: %ld", p->neworder, lc);
446 	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
447 		warnx("%s: bad JSON object", p->neworder);
448 	else if (!json_parse_order(j, order))
449 		warnx("%s: bad order", p->neworder);
450 	else if (order->status == ORDER_INVALID)
451 		warnx("%s: order invalid", p->neworder);
452 	else
453 		rc = 1;
454 
455 	if (rc == 0 || verbose > 1)
456 		buf_dump(&c->buf);
457 
458 	free(req);
459 	json_free(j);
460 	return rc;
461 }
462 
463 /*
464  * Update order status
465  */
466 static int
467 doupdorder(struct conn *c, struct order *order)
468 {
469 	struct jsmnn	*j = NULL;
470 	int		 rc = 0;
471 	long		 lc;
472 
473 	if ((lc = sreq(c, order->uri, 1, "", NULL)) < 0)
474 		warnx("%s: bad comm", order->uri);
475 	else if (lc != 200)
476 		warnx("%s: bad HTTP: %ld", order->uri, lc);
477 	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
478 		warnx("%s: bad JSON object", order->uri);
479 	else if (!json_parse_upd_order(j, order))
480 		warnx("%s: bad order", order->uri);
481 	else
482 		rc = 1;
483 
484 	if (rc == 0 || verbose > 1)
485 		buf_dump(&c->buf);
486 
487 	json_free(j);
488 	return rc;
489 }
490 
491 /*
492  * Request a challenge for the given domain name.
493  * This must be called for each name "alt".
494  * On non-zero exit, fills in "chng" with the challenge.
495  */
496 static int
497 dochngreq(struct conn *c, const char *auth, struct chng *chng)
498 {
499 	int		 rc = 0;
500 	long		 lc;
501 	struct jsmnn	*j = NULL;
502 
503 	dodbg("%s: %s", __func__, auth);
504 
505 	if ((lc = sreq(c, auth, 1, "", NULL)) < 0)
506 		warnx("%s: bad comm", auth);
507 	else if (lc != 200)
508 		warnx("%s: bad HTTP: %ld", auth, lc);
509 	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
510 		warnx("%s: bad JSON object", auth);
511 	else if (!json_parse_challenge(j, chng))
512 		warnx("%s: bad challenge", auth);
513 	else
514 		rc = 1;
515 
516 	if (rc == 0 || verbose > 1)
517 		buf_dump(&c->buf);
518 	json_free(j);
519 	return rc;
520 }
521 
522 /*
523  * Tell the CA that a challenge response is in place.
524  */
525 static int
526 dochngresp(struct conn *c, const struct chng *chng)
527 {
528 	int	 rc = 0;
529 	long	 lc;
530 
531 	dodbg("%s: challenge", chng->uri);
532 
533 	if ((lc = sreq(c, chng->uri, 1, "{}", NULL)) < 0)
534 		warnx("%s: bad comm", chng->uri);
535 	else if (lc != 200 && lc != 201 && lc != 202)
536 		warnx("%s: bad HTTP: %ld", chng->uri, lc);
537 	else
538 		rc = 1;
539 
540 	if (rc == 0 || verbose > 1)
541 		buf_dump(&c->buf);
542 	return rc;
543 }
544 
545 /*
546  * Submit our csr to the CA.
547  */
548 static int
549 docert(struct conn *c, const char *uri, const char *csr)
550 {
551 	char	*req;
552 	int	 rc = 0;
553 	long	 lc;
554 
555 	dodbg("%s: certificate", uri);
556 
557 	if ((req = json_fmt_newcert(csr)) == NULL)
558 		warnx("json_fmt_newcert");
559 	else if ((lc = sreq(c, uri, 1, req, NULL)) < 0)
560 		warnx("%s: bad comm", uri);
561 	else if (lc != 200)
562 		warnx("%s: bad HTTP: %ld", uri, lc);
563 	else if (c->buf.sz == 0 || c->buf.buf == NULL)
564 		warnx("%s: empty response", uri);
565 	else
566 		rc = 1;
567 
568 	if (rc == 0 || verbose > 1)
569 		buf_dump(&c->buf);
570 	free(req);
571 	return rc;
572 }
573 
574 /*
575  * Get certificate from CA
576  */
577 static int
578 dogetcert(struct conn *c, const char *uri)
579 {
580 	int	 rc = 0;
581 	long	 lc;
582 
583 	dodbg("%s: certificate", uri);
584 
585 	if ((lc = sreq(c, uri, 1, "", NULL)) < 0)
586 		warnx("%s: bad comm", uri);
587 	else if (lc != 200)
588 		warnx("%s: bad HTTP: %ld", uri, lc);
589 	else if (c->buf.sz == 0 || c->buf.buf == NULL)
590 		warnx("%s: empty response", uri);
591 	else
592 		rc = 1;
593 
594 	if (rc == 0 || verbose > 1)
595 		buf_dump(&c->buf);
596 
597 	return rc;
598 }
599 
600 static int
601 dorevoke(struct conn *c, const char *addr, const char *cert)
602 {
603 	char		*req;
604 	int		 rc = 0;
605 	long		 lc = 0;
606 
607 	dodbg("%s: revocation", addr);
608 
609 	if ((req = json_fmt_revokecert(cert)) == NULL)
610 		warnx("json_fmt_revokecert");
611 	else if ((lc = sreq(c, addr, 1, req, NULL)) < 0)
612 		warnx("%s: bad comm", addr);
613 	else if (lc != 200 && lc != 201 && lc != 409)
614 		warnx("%s: bad HTTP: %ld", addr, lc);
615 	else
616 		rc = 1;
617 
618 	if (lc == 409)
619 		warnx("%s: already revoked", addr);
620 
621 	if (rc == 0 || verbose > 1)
622 		buf_dump(&c->buf);
623 	free(req);
624 	return rc;
625 }
626 
627 /*
628  * Look up directories from the certificate authority.
629  */
630 static int
631 dodirs(struct conn *c, const char *addr, struct capaths *paths)
632 {
633 	struct jsmnn	*j = NULL;
634 	long		 lc;
635 	int		 rc = 0;
636 
637 	dodbg("%s: directories", addr);
638 
639 	if ((lc = nreq(c, addr)) < 0)
640 		warnx("%s: bad comm", addr);
641 	else if (lc != 200 && lc != 201)
642 		warnx("%s: bad HTTP: %ld", addr, lc);
643 	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
644 		warnx("json_parse");
645 	else if (!json_parse_capaths(j, paths))
646 		warnx("%s: bad CA paths", addr);
647 	else
648 		rc = 1;
649 
650 	if (rc == 0 || verbose > 1)
651 		buf_dump(&c->buf);
652 	json_free(j);
653 	return rc;
654 }
655 
656 /*
657  * Communicate with the ACME server.
658  * We need the certificate we want to upload and our account key information.
659  */
660 int
661 netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
662     int revocate, struct authority_c *authority,
663     const char *const *alts, size_t altsz)
664 {
665 	int		 rc = 0;
666 	size_t		 i;
667 	char		*cert = NULL, *thumb = NULL, *url = NULL;
668 	struct conn	 c;
669 	struct capaths	 paths;
670 	struct order	 order;
671 	struct chng	*chngs = NULL;
672 	long		 lval;
673 
674 	memset(&paths, 0, sizeof(struct capaths));
675 	memset(&c, 0, sizeof(struct conn));
676 
677 	if (unveil(tls_default_ca_cert_file(), "r") == -1) {
678 		warn("unveil");
679 		goto out;
680 	}
681 
682 	if (pledge("stdio inet rpath", NULL) == -1) {
683 		warn("pledge");
684 		goto out;
685 	}
686 
687 	if (http_init() == -1) {
688 		warn("http_init");
689 		goto out;
690 	}
691 
692 	if (pledge("stdio inet", NULL) == -1) {
693 		warn("pledge");
694 		goto out;
695 	}
696 
697 	/*
698 	 * Wait until the acctproc, keyproc, and revokeproc have started up and
699 	 * are ready to serve us data.
700 	 * Then check whether revokeproc indicates that the certificate on file
701 	 * (if any) can be updated.
702 	 */
703 	if ((lval = readop(afd, COMM_ACCT_STAT)) == 0) {
704 		rc = 1;
705 		goto out;
706 	} else if (lval != ACCT_READY) {
707 		warnx("unknown operation from acctproc");
708 		goto out;
709 	}
710 
711 	if ((lval = readop(kfd, COMM_KEY_STAT)) == 0) {
712 		rc = 1;
713 		goto out;
714 	} else if (lval != KEY_READY) {
715 		warnx("unknown operation from keyproc");
716 		goto out;
717 	}
718 
719 	if ((lval = readop(rfd, COMM_REVOKE_RESP)) == 0) {
720 		rc = 1;
721 		goto out;
722 	} else if (lval != REVOKE_EXP && lval != REVOKE_OK) {
723 		warnx("unknown operation from revokeproc");
724 		goto out;
725 	}
726 
727 	/* If our certificate is up-to-date, return now. */
728 	if (lval == REVOKE_OK) {
729 		rc = 1;
730 		goto out;
731 	}
732 
733 	c.dfd = dfd;
734 	c.fd = afd;
735 
736 	/*
737 	 * Look up the API urls of the ACME server.
738 	 */
739 	if (!dodirs(&c, authority->api, &paths))
740 		goto out;
741 
742 	c.newnonce = paths.newnonce;
743 
744 	/* Check if our account already exists or create it. */
745 	if (!dochkacc(&c, &paths))
746 		goto out;
747 
748 	/*
749 	 * If we're meant to revoke, then wait for revokeproc to send us
750 	 * the certificate (if it's found at all).
751 	 * Following that, submit the request to the CA then notify the
752 	 * certproc, which will in turn notify the fileproc.
753 	 * XXX currently we can only sign with the account key, the RFC
754 	 * also mentions signing with the privat key of the cert itself.
755 	 */
756 	if (revocate) {
757 		if ((cert = readstr(rfd, COMM_CSR)) == NULL)
758 			goto out;
759 		if (!dorevoke(&c, paths.revokecert, cert))
760 			goto out;
761 		else if (writeop(cfd, COMM_CSR_OP, CERT_REVOKE) > 0)
762 			rc = 1;
763 		goto out;
764 	}
765 
766 	memset(&order, 0, sizeof(order));
767 
768 	if (!doneworder(&c, alts, altsz, &order, &paths))
769 		goto out;
770 
771 	chngs = calloc(order.authsz, sizeof(struct chng));
772 	if (chngs == NULL) {
773 		warn("calloc");
774 		goto out;
775 	}
776 
777 	/*
778 	 * Get thumbprint from acctproc. We will need it to construct
779 	 * a response to the challenge
780 	 */
781 	if (writeop(afd, COMM_ACCT, ACCT_THUMBPRINT) <= 0)
782 		goto out;
783 	else if ((thumb = readstr(afd, COMM_THUMB)) == NULL)
784 		goto out;
785 
786 	while(order.status != ORDER_VALID && order.status != ORDER_INVALID) {
787 		switch (order.status) {
788 		case ORDER_INVALID:
789 			warnx("order invalid");
790 			goto out;
791 		case ORDER_VALID:
792 			rc = 1;
793 			continue;
794 		case ORDER_PENDING:
795 			if (order.authsz < 1) {
796 				warnx("order is in state pending but no "
797 				    "authorizations know");
798 				goto out;
799 			}
800 			for (i = 0; i < order.authsz; i++) {
801 				if (!dochngreq(&c, order.auths[i], &chngs[i]))
802 					goto out;
803 
804 				dodbg("challenge, token: %s, uri: %s, status: "
805 				    "%d", chngs[i].token, chngs[i].uri,
806 				    chngs[i].status);
807 
808 				if (chngs[i].status == CHNG_VALID)
809 					continue;
810 
811 				if (chngs[i].retry++ >= RETRY_MAX) {
812 					warnx("%s: too many tries",
813 					    chngs[i].uri);
814 					goto out;
815 				}
816 
817 				if (writeop(Cfd, COMM_CHNG_OP, CHNG_SYN) <= 0)
818 					goto out;
819 				else if (writestr(Cfd, COMM_THUMB, thumb) <= 0)
820 					goto out;
821 				else if (writestr(Cfd, COMM_TOK,
822 				    chngs[i].token) <= 0)
823 					goto out;
824 
825 				/* Read that the challenge has been made. */
826 				if (readop(Cfd, COMM_CHNG_ACK) != CHNG_ACK)
827 					goto out;
828 
829 				/* Write to the CA that it's ready. */
830 				if (!dochngresp(&c, &chngs[i]))
831 					goto out;
832 			}
833 			break;
834 		case ORDER_READY:
835 			/*
836 			 * Write our acknowledgement that the challenges are
837 			 * over.
838 			 * The challenge process will remove all of the files.
839 			 */
840 			if (writeop(Cfd, COMM_CHNG_OP, CHNG_STOP) <= 0)
841 				goto out;
842 
843 			/* Wait to receive the certificate itself. */
844 			if ((cert = readstr(kfd, COMM_CERT)) == NULL)
845 				goto out;
846 			if (!docert(&c, order.finalize, cert))
847 				goto out;
848 			break;
849 		default:
850 			warnx("unhandled status: %d", order.status);
851 			goto out;
852 		}
853 		if (!doupdorder(&c, &order))
854 			goto out;
855 
856 		dodbg("order.status %d", order.status);
857 		if (order.status == ORDER_PENDING)
858 			sleep(RETRY_DELAY);
859 	}
860 
861 	if (order.status != ORDER_VALID)
862 		goto out;
863 
864 	if (order.certificate == NULL) {
865 		warnx("no certificate url received");
866 		goto out;
867 	}
868 
869 	if (!dogetcert(&c, order.certificate))
870 		goto out;
871 	else if (writeop(cfd, COMM_CSR_OP, CERT_UPDATE) <= 0)
872 		goto out;
873 	else if (writebuf(cfd, COMM_CSR, c.buf.buf, c.buf.sz) <= 0)
874 		goto out;
875 	rc = 1;
876 out:
877 	close(cfd);
878 	close(kfd);
879 	close(afd);
880 	close(Cfd);
881 	close(dfd);
882 	close(rfd);
883 	free(cert);
884 	free(url);
885 	free(thumb);
886 	free(c.kid);
887 	free(c.buf.buf);
888 	if (chngs != NULL)
889 		for (i = 0; i < order.authsz; i++)
890 			json_free_challenge(&chngs[i]);
891 	free(chngs);
892 	json_free_capaths(&paths);
893 	return rc;
894 }
895