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