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