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