GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/acme-client/netproc.c Lines: 0 331 0.0 %
Date: 2017-11-13 Branches: 0 240 0.0 %

Line Branch Exec Source
1
/*	$Id: netproc.c,v 1.13 2017/01/24 13:32:55 jsing 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
26
#include "http.h"
27
#include "extern.h"
28
#include "parse.h"
29
30
#define	RETRY_DELAY 5
31
#define RETRY_MAX 10
32
33
/*
34
 * Buffer used when collecting the results of a CURL transfer.
35
 */
36
struct	buf {
37
	char	*buf; /* binary buffer */
38
	size_t	 sz; /* length of buffer */
39
};
40
41
/*
42
 * Used for CURL communications.
43
 */
44
struct	conn {
45
	const char	  *na; /* nonce authority */
46
	int		   fd; /* acctproc handle */
47
	int		   dfd; /* dnsproc handle */
48
	struct buf	   buf; /* transfer buffer */
49
};
50
51
/*
52
 * If something goes wrong (or we're tracing output), we dump the
53
 * current transfer's data as a debug message.
54
 * Make sure that print all non-printable characters as question marks
55
 * so that we don't spam the console.
56
 * Also, consolidate white-space.
57
 * This of course will ruin string literals, but the intent here is just
58
 * to show the message, not to replicate it.
59
 */
60
static void
61
buf_dump(const struct buf *buf)
62
{
63
	size_t	 i;
64
	int	 j;
65
	char	*nbuf;
66
67
	if (buf->sz == 0)
68
		return;
69
	if ((nbuf = malloc(buf->sz)) == NULL)
70
		err(EXIT_FAILURE, "malloc");
71
72
	for (j = 0, i = 0; i < buf->sz; i++)
73
		if (isspace((int)buf->buf[i])) {
74
			nbuf[j++] = ' ';
75
			while (isspace((int)buf->buf[i]))
76
				i++;
77
			i--;
78
		} else
79
			nbuf[j++] = isprint((int)buf->buf[i]) ?
80
			    buf->buf[i] : '?';
81
	dodbg("transfer buffer: [%.*s] (%zu bytes)", j, nbuf, buf->sz);
82
	free(nbuf);
83
}
84
85
/*
86
 * Extract the domain and port from a URL.
87
 * The url must be formatted as schema://address[/stuff].
88
 * This returns NULL on failure.
89
 */
90
static char *
91
url2host(const char *host, short *port, char **path)
92
{
93
	char	*url, *ep;
94
95
	/* We only understand HTTP and HTTPS. */
96
97
	if (strncmp(host, "https://", 8) == 0) {
98
		*port = 443;
99
		if ((url = strdup(host + 8)) == NULL) {
100
			warn("strdup");
101
			return NULL;
102
		}
103
	} else if (strncmp(host, "http://", 7) == 0) {
104
		*port = 80;
105
		if ((url = strdup(host + 7)) == NULL) {
106
			warn("strdup");
107
			return NULL;
108
		}
109
	} else {
110
		warnx("%s: unknown schema", host);
111
		return NULL;
112
	}
113
114
	/* Terminate path part. */
115
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
	char		*host, *path;
184
	short		 port;
185
	size_t		 srcsz;
186
	ssize_t		 ssz;
187
	long		 code;
188
189
	if ((host = url2host(addr, &port, &path)) == NULL)
190
		return -1;
191
192
	if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
193
		free(host);
194
		free(path);
195
		return -1;
196
	}
197
	srcsz = ssz;
198
199
	g = http_get(src, srcsz, host, port, path, NULL, 0);
200
	free(host);
201
	free(path);
202
	if (g == NULL)
203
		return -1;
204
205
	code = g->code;
206
207
	/* Copy the body part into our buffer. */
208
209
	free(c->buf.buf);
210
	c->buf.sz = g->bodypartsz;
211
	c->buf.buf = malloc(c->buf.sz);
212
	memcpy(c->buf.buf, g->bodypart, c->buf.sz);
213
	http_get_free(g);
214
	if (c->buf.buf == NULL) {
215
		warn("malloc");
216
		return -1;
217
	}
218
	return code;
219
}
220
221
/*
222
 * Create and send a signed communication to the ACME server.
223
 * Stuff the response into the communication buffer.
224
 * Return <0 on failure on the HTTP error code otherwise.
225
 */
226
static long
227
sreq(struct conn *c, const char *addr, const char *req)
228
{
229
	struct httpget	*g;
230
	struct source	 src[MAX_SERVERS_DNS];
231
	char		*host, *path, *nonce, *reqsn;
232
	short		 port;
233
	struct httphead	*h;
234
	ssize_t		 ssz;
235
	long		 code;
236
237
	if ((host = url2host(c->na, &port, &path)) == NULL)
238
		return -1;
239
240
	if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
241
		free(host);
242
		free(path);
243
		return -1;
244
	}
245
246
	g = http_get(src, (size_t)ssz, host, port, path, NULL, 0);
247
	free(host);
248
	free(path);
249
	if (g == NULL)
250
		return -1;
251
252
	h = http_head_get("Replay-Nonce", g->head, g->headsz);
253
	if (h == NULL) {
254
		warnx("%s: no replay nonce", c->na);
255
		http_get_free(g);
256
		return -1;
257
	} else if ((nonce = strdup(h->val)) == NULL) {
258
		warn("strdup");
259
		http_get_free(g);
260
		return -1;
261
	}
262
	http_get_free(g);
263
264
	/*
265
	 * Send the nonce and request payload to the acctproc.
266
	 * This will create the proper JSON object we need.
267
	 */
268
269
	if (writeop(c->fd, COMM_ACCT, ACCT_SIGN) <= 0) {
270
		free(nonce);
271
		return -1;
272
	} else if (writestr(c->fd, COMM_PAY, req) <= 0) {
273
		free(nonce);
274
		return -1;
275
	} else if (writestr(c->fd, COMM_NONCE, nonce) <= 0) {
276
		free(nonce);
277
		return -1;
278
	}
279
	free(nonce);
280
281
	/* Now read back the signed payload. */
282
283
	if ((reqsn = readstr(c->fd, COMM_REQ)) == NULL)
284
		return -1;
285
286
	/* Now send the signed payload to the CA. */
287
288
	if ((host = url2host(addr, &port, &path)) == NULL) {
289
		free(reqsn);
290
		return -1;
291
	} else if ((ssz = urlresolve(c->dfd, host, src)) < 0) {
292
		free(host);
293
		free(path);
294
		free(reqsn);
295
		return -1;
296
	}
297
298
	g = http_get(src, (size_t)ssz, host, port, path, reqsn, strlen(reqsn));
299
300
	free(host);
301
	free(path);
302
	free(reqsn);
303
	if (g == NULL)
304
		return -1;
305
306
	/* Stuff response into parse buffer. */
307
308
	code = g->code;
309
310
	free(c->buf.buf);
311
	c->buf.sz = g->bodypartsz;
312
	c->buf.buf = malloc(c->buf.sz);
313
	memcpy(c->buf.buf, g->bodypart, c->buf.sz);
314
	http_get_free(g);
315
	if (c->buf.buf == NULL) {
316
		warn("malloc");
317
		return -1;
318
	}
319
	return code;
320
}
321
322
/*
323
 * Send to the CA that we want to authorise a new account.
324
 * This only happens once for a new account key.
325
 * Returns non-zero on success.
326
 */
327
static int
328
donewreg(struct conn *c, const char *agreement, const struct capaths *p)
329
{
330
	int		 rc = 0;
331
	char		*req;
332
	long		 lc;
333
334
	dodbg("%s: new-reg", p->newreg);
335
336
	if ((req = json_fmt_newreg(agreement)) == NULL)
337
		warnx("json_fmt_newreg");
338
	else if ((lc = sreq(c, p->newreg, req)) < 0)
339
		warnx("%s: bad comm", p->newreg);
340
	else if (lc != 200 && lc != 201)
341
		warnx("%s: bad HTTP: %ld", p->newreg, lc);
342
	else if (c->buf.buf == NULL || c->buf.sz == 0)
343
		warnx("%s: empty response", p->newreg);
344
	else
345
		rc = 1;
346
347
	if (rc == 0 || verbose > 1)
348
		buf_dump(&c->buf);
349
	free(req);
350
	return rc;
351
}
352
353
/*
354
 * Request a challenge for the given domain name.
355
 * This must happen for each name "alt".
356
 * On non-zero exit, fills in "chng" with the challenge.
357
 */
358
static int
359
dochngreq(struct conn *c, const char *alt, struct chng *chng,
360
    const struct capaths *p)
361
{
362
	int		 rc = 0;
363
	char		*req;
364
	long		 lc;
365
	struct jsmnn	*j = NULL;
366
367
	dodbg("%s: req-auth: %s", p->newauthz, alt);
368
369
	if ((req = json_fmt_newauthz(alt)) == NULL)
370
		warnx("json_fmt_newauthz");
371
	else if ((lc = sreq(c, p->newauthz, req)) < 0)
372
		warnx("%s: bad comm", p->newauthz);
373
	else if (lc != 200 && lc != 201)
374
		warnx("%s: bad HTTP: %ld", p->newauthz, lc);
375
	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
376
		warnx("%s: bad JSON object", p->newauthz);
377
	else if (!json_parse_challenge(j, chng))
378
		warnx("%s: bad challenge", p->newauthz);
379
	else
380
		rc = 1;
381
382
	if (rc == 0 || verbose > 1)
383
		buf_dump(&c->buf);
384
	json_free(j);
385
	free(req);
386
	return rc;
387
}
388
389
/*
390
 * Note to the CA that a challenge response is in place.
391
 */
392
static int
393
dochngresp(struct conn *c, const struct chng *chng, const char *th)
394
{
395
	int	 rc = 0;
396
	long	 lc;
397
	char	*req;
398
399
	dodbg("%s: challenge", chng->uri);
400
401
	if ((req = json_fmt_challenge(chng->token, th)) == NULL)
402
		warnx("json_fmt_challenge");
403
	else if ((lc = sreq(c, chng->uri, req)) < 0)
404
		warnx("%s: bad comm", chng->uri);
405
	else if (lc != 200 && lc != 201 && lc != 202)
406
		warnx("%s: bad HTTP: %ld", chng->uri, lc);
407
	else
408
		rc = 1;
409
410
	if (rc == 0 || verbose > 1)
411
		buf_dump(&c->buf);
412
	free(req);
413
	return rc;
414
}
415
416
/*
417
 * Check with the CA whether a challenge has been processed.
418
 * Note: we'll only do this a limited number of times, and pause for a
419
 * time between checks, but this happens in the caller.
420
 */
421
static int
422
dochngcheck(struct conn *c, struct chng *chng)
423
{
424
	int		 cc;
425
	long		 lc;
426
	struct jsmnn	*j;
427
428
	dodbg("%s: status", chng->uri);
429
430
	if ((lc = nreq(c, chng->uri)) < 0) {
431
		warnx("%s: bad comm", chng->uri);
432
		return 0;
433
	} else if (lc != 200 && lc != 201 && lc != 202) {
434
		warnx("%s: bad HTTP: %ld", chng->uri, lc);
435
		buf_dump(&c->buf);
436
		return 0;
437
	} else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL) {
438
		warnx("%s: bad JSON object", chng->uri);
439
		buf_dump(&c->buf);
440
		return 0;
441
	} else if ((cc = json_parse_response(j)) == -1) {
442
		warnx("%s: bad response", chng->uri);
443
		buf_dump(&c->buf);
444
		json_free(j);
445
		return 0;
446
	} else if (cc > 0)
447
		chng->status = 1;
448
449
	json_free(j);
450
	return 1;
451
}
452
453
static int
454
dorevoke(struct conn *c, const char *addr, const char *cert)
455
{
456
	char		*req;
457
	int		 rc = 0;
458
	long		 lc = 0;
459
460
	dodbg("%s: revocation", addr);
461
462
	if ((req = json_fmt_revokecert(cert)) == NULL)
463
		warnx("json_fmt_revokecert");
464
	else if ((lc = sreq(c, addr, req)) < 0)
465
		warnx("%s: bad comm", addr);
466
	else if (lc != 200 && lc != 201 && lc != 409)
467
		warnx("%s: bad HTTP: %ld", addr, lc);
468
	else
469
		rc = 1;
470
471
	if (lc == 409)
472
		warnx("%s: already revoked", addr);
473
474
	if (rc == 0 || verbose > 1)
475
		buf_dump(&c->buf);
476
	free(req);
477
	return rc;
478
}
479
480
/*
481
 * Submit our certificate to the CA.
482
 * This, upon success, will return the signed CA.
483
 */
484
static int
485
docert(struct conn *c, const char *addr, const char *cert)
486
{
487
	char	*req;
488
	int	 rc = 0;
489
	long	 lc;
490
491
	dodbg("%s: certificate", addr);
492
493
	if ((req = json_fmt_newcert(cert)) == NULL)
494
		warnx("json_fmt_newcert");
495
	else if ((lc = sreq(c, addr, req)) < 0)
496
		warnx("%s: bad comm", addr);
497
	else if (lc != 200 && lc != 201)
498
		warnx("%s: bad HTTP: %ld", addr, lc);
499
	else if (c->buf.sz == 0 || c->buf.buf == NULL)
500
		warnx("%s: empty response", addr);
501
	else
502
		rc = 1;
503
504
	if (rc == 0 || verbose > 1)
505
		buf_dump(&c->buf);
506
	free(req);
507
	return rc;
508
}
509
510
/*
511
 * Look up directories from the certificate authority.
512
 */
513
static int
514
dodirs(struct conn *c, const char *addr, struct capaths *paths)
515
{
516
	struct jsmnn	*j = NULL;
517
	long		 lc;
518
	int		 rc = 0;
519
520
	dodbg("%s: directories", addr);
521
522
	if ((lc = nreq(c, addr)) < 0)
523
		warnx("%s: bad comm", addr);
524
	else if (lc != 200 && lc != 201)
525
		warnx("%s: bad HTTP: %ld", addr, lc);
526
	else if ((j = json_parse(c->buf.buf, c->buf.sz)) == NULL)
527
		warnx("json_parse");
528
	else if (!json_parse_capaths(j, paths))
529
		warnx("%s: bad CA paths", addr);
530
	else
531
		rc = 1;
532
533
	if (rc == 0 || verbose > 1)
534
		buf_dump(&c->buf);
535
	json_free(j);
536
	return rc;
537
}
538
539
/*
540
 * Request the full chain certificate.
541
 */
542
static int
543
dofullchain(struct conn *c, const char *addr)
544
{
545
	int	 rc = 0;
546
	long	 lc;
547
548
	dodbg("%s: full chain", addr);
549
550
	if ((lc = nreq(c, addr)) < 0)
551
		warnx("%s: bad comm", addr);
552
	else if (lc != 200 && lc != 201)
553
		warnx("%s: bad HTTP: %ld", addr, lc);
554
	else
555
		rc = 1;
556
557
	if (rc == 0 || verbose > 1)
558
		buf_dump(&c->buf);
559
	return rc;
560
}
561
562
/*
563
 * Here we communicate with the ACME server.
564
 * For this, we'll need the certificate we want to upload and our
565
 * account key information.
566
 */
567
int
568
netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
569
    int newacct, int revocate, struct authority_c *authority,
570
    const char *const *alts,size_t altsz, const char *agreement)
571
{
572
	int		 rc = 0;
573
	size_t		 i;
574
	char		*cert = NULL, *thumb = NULL, *url = NULL;
575
	struct conn	 c;
576
	struct capaths	 paths;
577
	struct chng	*chngs = NULL;
578
	long		 lval;
579
580
	memset(&paths, 0, sizeof(struct capaths));
581
	memset(&c, 0, sizeof(struct conn));
582
583
	if (pledge("stdio inet rpath flock cpath wpath", NULL) == -1) {
584
		warn("pledge");
585
		goto out;
586
	}
587
588
	if (http_init() == -1) {
589
		warn("http_init");
590
		goto out;
591
	}
592
593
	if (pledge("stdio inet flock rpath cpath wpath", NULL) == -1) {
594
		warn("pledge");
595
		goto out;
596
	}
597
598
	/*
599
	 * Wait until the acctproc, keyproc, and revokeproc have started
600
	 * up and are ready to serve us data.
601
	 * There's no point in running if these don't work.
602
	 * Then check whether revokeproc indicates that the certificate
603
	 * on file (if any) can be updated.
604
	 */
605
606
	if ((lval = readop(afd, COMM_ACCT_STAT)) == 0) {
607
		rc = 1;
608
		goto out;
609
	} else if (lval != ACCT_READY) {
610
		warnx("unknown operation from acctproc");
611
		goto out;
612
	}
613
614
	if ((lval = readop(kfd, COMM_KEY_STAT)) == 0) {
615
		rc = 1;
616
		goto out;
617
	} else if (lval != KEY_READY) {
618
		warnx("unknown operation from keyproc");
619
		goto out;
620
	}
621
622
	if ((lval = readop(rfd, COMM_REVOKE_RESP)) == 0) {
623
		rc = 1;
624
		goto out;
625
	} else if (lval != REVOKE_EXP && lval != REVOKE_OK) {
626
		warnx("unknown operation from revokeproc");
627
		goto out;
628
	}
629
630
	/* If our certificate is up-to-date, return now. */
631
632
	if (lval == REVOKE_OK) {
633
		rc = 1;
634
		goto out;
635
	}
636
637
	/* Allocate main state. */
638
639
	chngs = calloc(altsz, sizeof(struct chng));
640
	if (chngs == NULL) {
641
		warn("calloc");
642
		goto out;
643
	}
644
645
	c.dfd = dfd;
646
	c.fd = afd;
647
	c.na = authority->api;
648
649
	/*
650
	 * Look up the domain of the ACME server.
651
	 * We'll use this ourselves instead of having libcurl do the DNS
652
	 * resolution itself.
653
	 */
654
	if (!dodirs(&c, c.na, &paths))
655
		goto out;
656
657
	/*
658
	 * If we're meant to revoke, then wait for revokeproc to send us
659
	 * the certificate (if it's found at all).
660
	 * Following that, submit the request to the CA then notify the
661
	 * certproc, which will in turn notify the fileproc.
662
	 */
663
664
	if (revocate) {
665
		if ((cert = readstr(rfd, COMM_CSR)) == NULL)
666
			goto out;
667
		if (!dorevoke(&c, paths.revokecert, cert))
668
			goto out;
669
		else if (writeop(cfd, COMM_CSR_OP, CERT_REVOKE) > 0)
670
			rc = 1;
671
		goto out;
672
	}
673
674
	/* If new, register with the CA server. */
675
676
	if (newacct && ! donewreg(&c, agreement, &paths))
677
		goto out;
678
679
	/* Pre-authorise all domains with CA server. */
680
681
	for (i = 0; i < altsz; i++)
682
		if (!dochngreq(&c, alts[i], &chngs[i], &paths))
683
			goto out;
684
685
	/*
686
	 * We now have our challenges.
687
	 * We need to ask the acctproc for the thumbprint.
688
	 * We'll combine this to the challenge to create our response,
689
	 * which will be orchestrated by the chngproc.
690
	 */
691
692
	if (writeop(afd, COMM_ACCT, ACCT_THUMBPRINT) <= 0)
693
		goto out;
694
	else if ((thumb = readstr(afd, COMM_THUMB)) == NULL)
695
		goto out;
696
697
	/* We'll now ask chngproc to build the challenge. */
698
699
	for (i = 0; i < altsz; i++) {
700
		if (writeop(Cfd, COMM_CHNG_OP, CHNG_SYN) <= 0)
701
			goto out;
702
		else if (writestr(Cfd, COMM_THUMB, thumb) <= 0)
703
			goto out;
704
		else if (writestr(Cfd, COMM_TOK, chngs[i].token) <= 0)
705
			goto out;
706
707
		/* Read that the challenge has been made. */
708
709
		if (readop(Cfd, COMM_CHNG_ACK) != CHNG_ACK)
710
			goto out;
711
712
		/* Write to the CA that it's ready. */
713
714
		if (!dochngresp(&c, &chngs[i], thumb))
715
			goto out;
716
	}
717
718
	/*
719
	 * We now wait on the ACME server for each domain.
720
	 * Connect to the server (assume it's the same server) once
721
	 * every five seconds.
722
	 */
723
724
	for (i = 0; i < altsz; i++) {
725
		if (chngs[i].status == 1)
726
			continue;
727
728
		if (chngs[i].retry++ >= RETRY_MAX) {
729
			warnx("%s: too many tries", chngs[i].uri);
730
			goto out;
731
		}
732
733
		/* Sleep before every attempt. */
734
		sleep(RETRY_DELAY);
735
		if (!dochngcheck(&c, &chngs[i]))
736
			goto out;
737
	}
738
739
	/*
740
	 * Write our acknowledgement that the challenges are over.
741
	 * The challenge process will remove all of the files.
742
	 */
743
744
	if (writeop(Cfd, COMM_CHNG_OP, CHNG_STOP) <= 0)
745
		goto out;
746
747
	/* Wait to receive the certificate itself. */
748
749
	if ((cert = readstr(kfd, COMM_CERT)) == NULL)
750
		goto out;
751
752
	/*
753
	 * Otherwise, submit the CA for signing, download the signed
754
	 * copy, and ship that into the certificate process for copying.
755
	 */
756
757
	if (!docert(&c, paths.newcert, cert))
758
		goto out;
759
	else if (writeop(cfd, COMM_CSR_OP, CERT_UPDATE) <= 0)
760
		goto out;
761
	else if (writebuf(cfd, COMM_CSR, c.buf.buf, c.buf.sz) <= 0)
762
		goto out;
763
764
	/*
765
	 * Read back the issuer from the certproc.
766
	 * Then contact the issuer to get the certificate chain.
767
	 * Write this chain directly back to the certproc.
768
	 */
769
770
	if ((url = readstr(cfd, COMM_ISSUER)) == NULL)
771
		goto out;
772
	else if (!dofullchain(&c, url))
773
		goto out;
774
	else if (writebuf(cfd, COMM_CHAIN, c.buf.buf, c.buf.sz) <= 0)
775
		goto out;
776
777
	rc = 1;
778
out:
779
	close(cfd);
780
	close(kfd);
781
	close(afd);
782
	close(Cfd);
783
	close(dfd);
784
	close(rfd);
785
	free(cert);
786
	free(url);
787
	free(thumb);
788
	free(c.buf.buf);
789
	if (chngs != NULL)
790
		for (i = 0; i < altsz; i++)
791
			json_free_challenge(&chngs[i]);
792
	free(chngs);
793
	json_free_capaths(&paths);
794
	return rc;
795
}