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