GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ikectl/ikeca.c Lines: 0 451 0.0 %
Date: 2017-11-13 Branches: 0 228 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ikeca.c,v 1.47 2017/11/08 09:33:37 patrick Exp $	*/
2
3
/*
4
 * Copyright (c) 2010 Jonathan Gray <jsg@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
#include <stdio.h>
22
#include <unistd.h>
23
#include <err.h>
24
#include <errno.h>
25
#include <string.h>
26
#include <stdlib.h>
27
#include <pwd.h>
28
#include <fcntl.h>
29
#include <fts.h>
30
#include <dirent.h>
31
#include <limits.h>
32
33
#include <openssl/rand.h>
34
#include <openssl/rsa.h>
35
#include <openssl/pem.h>
36
37
#include "types.h"
38
#include "parser.h"
39
40
#ifndef PREFIX
41
#define PREFIX		""
42
#endif
43
#ifndef SSLDIR
44
#define SSLDIR		PREFIX "/etc/ssl"
45
#endif
46
#define SSL_CNF		SSLDIR "/openssl.cnf"
47
#define X509_CNF	SSLDIR "/x509v3.cnf"
48
#define IKECA_CNF	SSLDIR "/ikeca.cnf"
49
#define KEYBASE		PREFIX "/etc/iked"
50
#ifndef EXPDIR
51
#define EXPDIR		PREFIX "/usr/share/iked"
52
#endif
53
54
#ifndef PATH_OPENSSL
55
#define PATH_OPENSSL	"/usr/bin/openssl"
56
#endif
57
#ifndef PATH_ZIP
58
#define PATH_ZIP	"/usr/local/bin/zip"
59
#endif
60
#ifndef PATH_TAR
61
#define PATH_TAR	"/bin/tar"
62
#endif
63
64
struct ca {
65
	char		 sslpath[PATH_MAX];
66
	char		 passfile[PATH_MAX];
67
	char		 index[PATH_MAX];
68
	char		 serial[PATH_MAX];
69
	char		 sslcnf[PATH_MAX];
70
	char		 extcnf[PATH_MAX];
71
	char		 batch[PATH_MAX];
72
	char		*caname;
73
};
74
75
struct {
76
	char	*dir;
77
	mode_t	 mode;
78
} hier[] = {
79
	{ "",		0755 },
80
	{ "/ca",	0755 },
81
	{ "/certs",	0755 },
82
	{ "/crls",	0755 },
83
	{ "/export",	0755 },
84
	{ "/private",	0700 }
85
};
86
87
/* explicitly list allowed variables */
88
char *ca_env[][2] = {
89
	{ "$ENV::CADB", NULL },
90
	{ "$ENV::CASERIAL", NULL },
91
	{ "$ENV::CERTFQDN", NULL },
92
	{ "$ENV::CERTIP", NULL },
93
	{ "$ENV::CERTPATHLEN", NULL },
94
	{ "$ENV::CERTUSAGE", NULL },
95
	{ "$ENV::CERT_C", NULL },
96
	{ "$ENV::CERT_CN", NULL },
97
	{ "$ENV::CERT_EMAIL", NULL },
98
	{ "$ENV::CERT_L", NULL },
99
	{ "$ENV::CERT_O", NULL },
100
	{ "$ENV::CERT_OU", NULL },
101
	{ "$ENV::CERT_ST", NULL },
102
	{ "$ENV::EXTCERTUSAGE", NULL },
103
	{ "$ENV::NSCERTTYPE", NULL },
104
	{ "$ENV::REQ_EXT", NULL },
105
	{ NULL }
106
};
107
108
int		 ca_sign(struct ca *, char *, int);
109
int		 ca_request(struct ca *, char *, int);
110
void		 ca_newpass(char *, char *);
111
int		 fcopy(char *, char *, mode_t);
112
void		 fcopy_env(const char *, const char *, mode_t);
113
int		 rm_dir(char *);
114
void		 ca_hier(char *);
115
void		 ca_setenv(const char *, const char *);
116
void		 ca_clrenv(void);
117
void		 ca_setcnf(struct ca *, const char *);
118
void		 ca_create_index(struct ca *);
119
120
/* util.c */
121
int		 expand_string(char *, size_t, const char *, const char *);
122
123
int
124
ca_delete(struct ca *ca)
125
{
126
	return (rm_dir(ca->sslpath));
127
}
128
129
int
130
ca_key_create(struct ca *ca, char *keyname)
131
{
132
	struct stat		 st;
133
	char			 cmd[PATH_MAX * 2];
134
	char			 path[PATH_MAX];
135
136
	snprintf(path, sizeof(path), "%s/private/%s.key", ca->sslpath, keyname);
137
138
	/* don't recreate key if one is already present */
139
	if (stat(path, &st) == 0) {
140
		return (0);
141
	}
142
143
	snprintf(cmd, sizeof(cmd),
144
	    "%s genrsa -out %s 2048",
145
	    PATH_OPENSSL, path);
146
	system(cmd);
147
	chmod(path, 0600);
148
149
	return (0);
150
}
151
152
int
153
ca_key_import(struct ca *ca, char *keyname, char *import)
154
{
155
	struct stat		 st;
156
	char			 dst[PATH_MAX];
157
158
	if (stat(import, &st) != 0) {
159
		warn("could not access keyfile %s", import);
160
		return (1);
161
	}
162
163
	snprintf(dst, sizeof(dst), "%s/private/%s.key", ca->sslpath, keyname);
164
	fcopy(import, dst, 0600);
165
166
	return (0);
167
}
168
169
int
170
ca_key_delete(struct ca *ca, char *keyname)
171
{
172
	char			 path[PATH_MAX];
173
174
	snprintf(path, sizeof(path), "%s/private/%s.key", ca->sslpath, keyname);
175
	unlink(path);
176
177
	return (0);
178
}
179
180
int
181
ca_delkey(struct ca *ca, char *keyname)
182
{
183
	char		file[PATH_MAX];
184
185
	snprintf(file, sizeof(file), "%s/%s.crt", ca->sslpath, keyname);
186
	unlink(file);
187
188
	snprintf(file, sizeof(file), "%s/private/%s.key", ca->sslpath, keyname);
189
	unlink(file);
190
191
	snprintf(file, sizeof(file), "%s/private/%s.csr", ca->sslpath, keyname);
192
	unlink(file);
193
194
	snprintf(file, sizeof(file), "%s/private/%s.pfx", ca->sslpath, keyname);
195
	unlink(file);
196
197
	return (0);
198
}
199
200
int
201
ca_request(struct ca *ca, char *keyname, int type)
202
{
203
	char		cmd[PATH_MAX * 2];
204
	char		hostname[HOST_NAME_MAX+1];
205
	char		name[128];
206
	char		path[PATH_MAX];
207
208
	ca_setenv("$ENV::CERT_CN", keyname);
209
210
	strlcpy(name, keyname, sizeof(name));
211
212
	if (type == HOST_IPADDR) {
213
		ca_setenv("$ENV::CERTIP", name);
214
		ca_setenv("$ENV::REQ_EXT", "x509v3_IPAddr");
215
	} else if (type == HOST_FQDN) {
216
		if (!strcmp(keyname, "local")) {
217
			if (gethostname(hostname, sizeof(hostname)))
218
				err(1, "gethostname");
219
			strlcpy(name, hostname, sizeof(name));
220
		}
221
		ca_setenv("$ENV::CERTFQDN", name);
222
		ca_setenv("$ENV::REQ_EXT", "x509v3_FQDN");
223
	} else {
224
		errx(1, "unknown host type %d", type);
225
	}
226
227
	ca_setcnf(ca, keyname);
228
229
	snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname);
230
	snprintf(cmd, sizeof(cmd), "%s req %s-new"
231
	    " -key %s/private/%s.key -out %s -config %s",
232
	    PATH_OPENSSL, ca->batch, ca->sslpath, keyname,
233
	    path, ca->sslcnf);
234
235
	system(cmd);
236
	chmod(path, 0600);
237
238
	return (0);
239
}
240
241
int
242
ca_sign(struct ca *ca, char *keyname, int type)
243
{
244
	char		cmd[PATH_MAX * 2];
245
	const char	*extensions = NULL;
246
247
	if (type == HOST_IPADDR) {
248
		extensions = "x509v3_IPAddr";
249
	} else if (type == HOST_FQDN) {
250
		extensions = "x509v3_FQDN";
251
	} else {
252
		errx(1, "unknown host type %d", type);
253
	}
254
255
	ca_create_index(ca);
256
257
	ca_setenv("$ENV::CADB", ca->index);
258
	ca_setenv("$ENV::CASERIAL", ca->serial);
259
	ca_setcnf(ca, keyname);
260
261
	snprintf(cmd, sizeof(cmd),
262
	    "%s ca -config %s -keyfile %s/private/ca.key"
263
	    " -cert %s/ca.crt"
264
	    " -extfile %s -extensions %s -out %s/%s.crt"
265
	    " -in %s/private/%s.csr"
266
	    " -passin file:%s -outdir %s -batch",
267
	    PATH_OPENSSL, ca->sslcnf, ca->sslpath,
268
	    ca->sslpath,
269
	    ca->extcnf, extensions, ca->sslpath, keyname,
270
	    ca->sslpath, keyname,
271
	    ca->passfile, ca->sslpath);
272
273
	system(cmd);
274
275
	return (0);
276
}
277
278
int
279
ca_certificate(struct ca *ca, char *keyname, int type, int action)
280
{
281
	ca_clrenv();
282
283
	switch (action) {
284
	case CA_SERVER:
285
		ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth");
286
		ca_setenv("$ENV::NSCERTTYPE", "server");
287
		ca_setenv("$ENV::CERTUSAGE",
288
		    "digitalSignature,keyEncipherment");
289
		break;
290
	case CA_CLIENT:
291
		ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth");
292
		ca_setenv("$ENV::NSCERTTYPE", "client");
293
		ca_setenv("$ENV::CERTUSAGE",
294
		    "digitalSignature,keyAgreement");
295
		break;
296
	case CA_OCSP:
297
		ca_setenv("$ENV::EXTCERTUSAGE", "OCSPSigning");
298
		ca_setenv("$ENV::CERTUSAGE",
299
		    "nonRepudiation,digitalSignature,keyEncipherment");
300
		break;
301
	default:
302
		break;
303
	}
304
305
	ca_key_create(ca, keyname);
306
	ca_request(ca, keyname, type);
307
	ca_sign(ca, keyname, type);
308
309
	return (0);
310
}
311
312
int
313
ca_key_install(struct ca *ca, char *keyname, char *dir)
314
{
315
	struct stat	 st;
316
	char		 cmd[PATH_MAX * 2];
317
	char		 src[PATH_MAX];
318
	char		 dst[PATH_MAX];
319
	char		*p = NULL;
320
321
	snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath, keyname);
322
	if (stat(src, &st) == -1) {
323
		if (errno == ENOENT)
324
			printf("key for '%s' does not exist\n", ca->caname);
325
		else
326
			warn("could not access key");
327
		return (1);
328
	}
329
330
	if (dir == NULL)
331
		p = dir = strdup(KEYBASE);
332
333
	ca_hier(dir);
334
335
	snprintf(dst, sizeof(dst), "%s/private/local.key", dir);
336
	fcopy(src, dst, 0600);
337
338
	snprintf(cmd, sizeof(cmd), "%s rsa -out %s/local.pub"
339
	    " -in %s/private/local.key -pubout", PATH_OPENSSL, dir, dir);
340
	system(cmd);
341
342
	free(p);
343
344
	return (0);
345
}
346
347
int
348
ca_cert_install(struct ca *ca, char *keyname, char *dir)
349
{
350
	char		 src[PATH_MAX];
351
	char		 dst[PATH_MAX];
352
	int		 r;
353
	char		*p = NULL;
354
355
	if (dir == NULL)
356
		p = dir = strdup(KEYBASE);
357
358
	ca_hier(dir);
359
360
	if ((r = ca_key_install(ca, keyname, dir)) != 0) {
361
		free(dir);
362
		return (r);
363
	}
364
365
	snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname);
366
	snprintf(dst, sizeof(dst), "%s/certs/%s.crt", dir, keyname);
367
	fcopy(src, dst, 0644);
368
369
	free(p);
370
371
	return (0);
372
}
373
374
void
375
ca_newpass(char *passfile, char *password)
376
{
377
	FILE	*f;
378
	char	*pass;
379
	char	 prev[_PASSWORD_LEN + 1];
380
381
	if (password != NULL) {
382
		pass = password;
383
		goto done;
384
	}
385
386
	pass = getpass("CA passphrase:");
387
	if (pass == NULL || *pass == '\0')
388
		err(1, "password not set");
389
390
	strlcpy(prev, pass, sizeof(prev));
391
	pass = getpass("Retype CA passphrase:");
392
	if (pass == NULL || strcmp(prev, pass) != 0)
393
		errx(1, "passphrase does not match!");
394
395
 done:
396
	if ((f = fopen(passfile, "wb")) == NULL)
397
		err(1, "could not open passfile %s", passfile);
398
	chmod(passfile, 0600);
399
400
	fprintf(f, "%s\n%s\n", pass, pass);
401
402
	fclose(f);
403
}
404
405
int
406
ca_create(struct ca *ca)
407
{
408
	char			 cmd[PATH_MAX * 2];
409
	char			 path[PATH_MAX];
410
411
	ca_clrenv();
412
413
	snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath);
414
	snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out"
415
	    " %s -passout file:%s 2048", PATH_OPENSSL,
416
	    path, ca->passfile);
417
	system(cmd);
418
	chmod(path, 0600);
419
420
	ca_setenv("$ENV::CERT_CN", "VPN CA");
421
	ca_setenv("$ENV::REQ_EXT", "x509v3_CA");
422
	ca_setcnf(ca, "ca");
423
424
	snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath);
425
	snprintf(cmd, sizeof(cmd), "%s req %s-new"
426
	    " -key %s/private/ca.key"
427
	    " -config %s -out %s -passin file:%s", PATH_OPENSSL,
428
	    ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile);
429
	system(cmd);
430
	chmod(path, 0600);
431
432
	snprintf(cmd, sizeof(cmd), "%s x509 -req -days 365"
433
	    " -in %s/private/ca.csr -signkey %s/private/ca.key"
434
	    " -sha256"
435
	    " -extfile %s -extensions x509v3_CA -out %s/ca.crt -passin file:%s",
436
	    PATH_OPENSSL, ca->sslpath, ca->sslpath, ca->extcnf, ca->sslpath,
437
	    ca->passfile);
438
	system(cmd);
439
440
	/* Create the CRL revocation list */
441
	ca_revoke(ca, NULL);
442
443
	return (0);
444
}
445
446
int
447
ca_install(struct ca *ca, char *dir)
448
{
449
	struct stat	 st;
450
	char		 src[PATH_MAX];
451
	char		 dst[PATH_MAX];
452
	char		*p = NULL;
453
454
	snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
455
	if (stat(src, &st) == -1) {
456
		printf("CA '%s' does not exist\n", ca->caname);
457
		return (1);
458
	}
459
460
	if (dir == NULL)
461
		p = dir = strdup(KEYBASE);
462
463
	ca_hier(dir);
464
465
	snprintf(dst, sizeof(dst), "%s/ca/ca.crt", dir);
466
	if (fcopy(src, dst, 0644) == 0)
467
		printf("certificate for CA '%s' installed into %s\n",
468
		    ca->caname, dst);
469
470
	snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
471
	if (stat(src, &st) == 0) {
472
		snprintf(dst, sizeof(dst), "%s/crls/ca.crl", dir);
473
		if (fcopy(src, dst, 0644) == 0)
474
			printf("CRL for CA '%s' installed to %s\n",
475
			    ca->caname, dst);
476
	}
477
478
	free(p);
479
480
	return (0);
481
}
482
483
int
484
ca_show_certs(struct ca *ca, char *name)
485
{
486
	DIR		*dir;
487
	struct dirent	*de;
488
	char		 cmd[PATH_MAX * 2];
489
	char		 path[PATH_MAX];
490
	char		*p;
491
	struct stat	 st;
492
493
	if (name != NULL) {
494
		snprintf(path, sizeof(path), "%s/%s.crt",
495
		    ca->sslpath, name);
496
		if (stat(path, &st) != 0)
497
			err(1, "could not open file %s.crt", name);
498
		snprintf(cmd, sizeof(cmd), "%s x509 -text"
499
		    " -in %s", PATH_OPENSSL, path);
500
		system(cmd);
501
		printf("\n");
502
		return (0);
503
	}
504
505
	if ((dir = opendir(ca->sslpath)) == NULL)
506
		err(1, "could not open directory %s", ca->sslpath);
507
508
	while ((de = readdir(dir)) != NULL) {
509
		if (de->d_namlen > 4) {
510
			p = de->d_name + de->d_namlen - 4;
511
			if (strcmp(".crt", p) != 0)
512
				continue;
513
			snprintf(path, sizeof(path), "%s/%s", ca->sslpath,
514
			    de->d_name);
515
			snprintf(cmd, sizeof(cmd), "%s x509 -subject"
516
			    " -fingerprint -dates -noout -in %s",
517
			    PATH_OPENSSL, path);
518
			system(cmd);
519
			printf("\n");
520
		}
521
	}
522
523
	closedir(dir);
524
525
	return (0);
526
}
527
528
int
529
fcopy(char *src, char *dst, mode_t mode)
530
{
531
	int		ifd, ofd;
532
	uint8_t		buf[BUFSIZ];
533
	ssize_t		r;
534
535
	if ((ifd = open(src, O_RDONLY)) == -1)
536
		err(1, "open %s", src);
537
538
	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
539
		int saved_errno = errno;
540
		close(ifd);
541
		errc(1, saved_errno, "open %s", dst);
542
	}
543
544
	while ((r = read(ifd, buf, sizeof(buf))) > 0) {
545
		write(ofd, buf, r);
546
	}
547
548
	close(ofd);
549
	close(ifd);
550
551
	return (r == -1);
552
}
553
554
void
555
fcopy_env(const char *src, const char *dst, mode_t mode)
556
{
557
	int		 ofd = -1, i;
558
	uint8_t		 buf[BUFSIZ];
559
	ssize_t		 r = -1, len;
560
	FILE		*ifp = NULL;
561
	int		 saved_errno;
562
563
	if ((ifp = fopen(src, "r")) == NULL)
564
		err(1, "fopen %s", src);
565
566
	if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
567
		goto done;
568
569
	while (fgets(buf, sizeof(buf), ifp) != NULL) {
570
		for (i = 0; ca_env[i][0] != NULL; i++) {
571
			if (ca_env[i][1] == NULL)
572
				continue;
573
			if (expand_string(buf, sizeof(buf),
574
			    ca_env[i][0], ca_env[i][1]) == -1)
575
				errx(1, "env %s value too long", ca_env[i][0]);
576
		}
577
		len = strlen(buf);
578
		if (write(ofd, buf, len) != len)
579
			goto done;
580
	}
581
582
	r = 0;
583
584
 done:
585
	saved_errno = errno;
586
	close(ofd);
587
	if (ifp != NULL)
588
		fclose(ifp);
589
	if (r == -1)
590
		errc(1, saved_errno, "open %s", dst);
591
}
592
593
int
594
rm_dir(char *path)
595
{
596
	FTS		*fts;
597
	FTSENT		*p;
598
	static char	*fpath[] = { NULL, NULL };
599
600
	fpath[0] = path;
601
	if ((fts = fts_open(fpath, FTS_PHYSICAL, NULL)) == NULL) {
602
		warn("fts_open %s", path);
603
		return (1);
604
	}
605
606
	while ((p = fts_read(fts)) != NULL) {
607
		switch (p->fts_info) {
608
		case FTS_DP:
609
		case FTS_DNR:
610
			if (rmdir(p->fts_accpath) == -1)
611
				warn("rmdir %s", p->fts_accpath);
612
			break;
613
		case FTS_F:
614
			if (unlink(p->fts_accpath) == -1)
615
				warn("unlink %s", p->fts_accpath);
616
			break;
617
		case FTS_D:
618
		case FTS_DOT:
619
		default:
620
			continue;
621
		}
622
	}
623
	fts_close(fts);
624
625
	return (0);
626
}
627
628
void
629
ca_hier(char *path)
630
{
631
	struct stat	 st;
632
	char		 dst[PATH_MAX];
633
	unsigned int	 i;
634
635
	for (i = 0; i < nitems(hier); i++) {
636
		strlcpy(dst, path, sizeof(dst));
637
		strlcat(dst, hier[i].dir, sizeof(dst));
638
		if (stat(dst, &st) != 0 && errno == ENOENT &&
639
		    mkdir(dst, hier[i].mode) != 0)
640
			err(1, "failed to create dir %s", dst);
641
	}
642
}
643
644
int
645
ca_export(struct ca *ca, char *keyname, char *myname, char *password)
646
{
647
	DIR		*dexp;
648
	struct dirent	*de;
649
	struct stat	 st;
650
	char		*pass;
651
	char		 prev[_PASSWORD_LEN + 1];
652
	char		 cmd[PATH_MAX * 2];
653
	char		 oname[PATH_MAX];
654
	char		 src[PATH_MAX];
655
	char		 dst[PATH_MAX];
656
	char		*p;
657
	char		 tpl[] = "/tmp/ikectl.XXXXXXXXXX";
658
	unsigned int	 i;
659
	int		 fd;
660
661
	if (keyname != NULL) {
662
		if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname))
663
			errx(1, "name too long");
664
	} else {
665
		strlcpy(oname, "ca", sizeof(oname));
666
	}
667
668
	/* colons are not valid characters in windows filenames... */
669
	while ((p = strchr(oname, ':')) != NULL)
670
		*p = '_';
671
672
	if (password != NULL)
673
		pass = password;
674
	else {
675
		pass = getpass("Export passphrase:");
676
		if (pass == NULL || *pass == '\0')
677
			err(1, "password not set");
678
679
		strlcpy(prev, pass, sizeof(prev));
680
		pass = getpass("Retype export passphrase:");
681
		if (pass == NULL || strcmp(prev, pass) != 0)
682
			errx(1, "passphrase does not match!");
683
	}
684
685
	if (keyname != NULL) {
686
		snprintf(cmd, sizeof(cmd), "env EXPASS=%s %s pkcs12 -export"
687
		    " -name %s -CAfile %s/ca.crt -inkey %s/private/%s.key"
688
		    " -in %s/%s.crt -out %s/private/%s.pfx -passout env:EXPASS"
689
		    " -passin file:%s", pass, PATH_OPENSSL, keyname,
690
		    ca->sslpath, ca->sslpath, keyname, ca->sslpath, keyname,
691
		    ca->sslpath, oname, ca->passfile);
692
		system(cmd);
693
	}
694
695
	snprintf(cmd, sizeof(cmd), "env EXPASS=%s %s pkcs12 -export"
696
	    " -caname '%s' -name '%s' -cacerts -nokeys"
697
	    " -in %s/ca.crt -out %s/ca.pfx -passout env:EXPASS -passin file:%s",
698
	    pass, PATH_OPENSSL, ca->caname, ca->caname, ca->sslpath,
699
	    ca->sslpath, ca->passfile);
700
	system(cmd);
701
702
	if ((p = mkdtemp(tpl)) == NULL)
703
		err(1, "could not create temp dir");
704
705
	chmod(p, 0755);
706
707
	for (i = 0; i < nitems(hier); i++) {
708
		strlcpy(dst, p, sizeof(dst));
709
		strlcat(dst, hier[i].dir, sizeof(dst));
710
		if (stat(dst, &st) != 0 && errno == ENOENT &&
711
		    mkdir(dst, hier[i].mode) != 0)
712
			err(1, "failed to create dir %s", dst);
713
	}
714
715
	/* create a file with the address of the peer to connect to */
716
	if (myname != NULL) {
717
		snprintf(dst, sizeof(dst), "%s/export/peer.txt", p);
718
		if ((fd = open(dst, O_WRONLY|O_CREAT, 0644)) == -1)
719
			err(1, "open %s", dst);
720
		write(fd, myname, strlen(myname));
721
		close(fd);
722
	}
723
724
	snprintf(src, sizeof(src), "%s/ca.pfx", ca->sslpath);
725
	snprintf(dst, sizeof(dst), "%s/export/ca.pfx", p);
726
	fcopy(src, dst, 0644);
727
728
	snprintf(src, sizeof(src), "%s/ca.crt", ca->sslpath);
729
	snprintf(dst, sizeof(dst), "%s/ca/ca.crt", p);
730
	fcopy(src, dst, 0644);
731
732
	snprintf(src, sizeof(src), "%s/ca.crl", ca->sslpath);
733
	if (stat(src, &st) == 0) {
734
		snprintf(dst, sizeof(dst), "%s/crls/ca.crl", p);
735
		fcopy(src, dst, 0644);
736
	}
737
738
	if (keyname != NULL) {
739
		snprintf(src, sizeof(src), "%s/private/%s.pfx", ca->sslpath,
740
		    oname);
741
		snprintf(dst, sizeof(dst), "%s/export/%s.pfx", p, oname);
742
		fcopy(src, dst, 0644);
743
744
		snprintf(src, sizeof(src), "%s/private/%s.key", ca->sslpath,
745
		    keyname);
746
		snprintf(dst, sizeof(dst), "%s/private/%s.key", p, keyname);
747
		fcopy(src, dst, 0600);
748
		snprintf(dst, sizeof(dst), "%s/private/local.key", p);
749
		fcopy(src, dst, 0600);
750
751
		snprintf(src, sizeof(src), "%s/%s.crt", ca->sslpath, keyname);
752
		snprintf(dst, sizeof(dst), "%s/certs/%s.crt", p, keyname);
753
		fcopy(src, dst, 0644);
754
755
		snprintf(cmd, sizeof(cmd), "%s rsa -out %s/local.pub"
756
		    " -in %s/private/%s.key -pubout", PATH_OPENSSL, p,
757
		    ca->sslpath, keyname);
758
		system(cmd);
759
	}
760
761
	if (stat(PATH_TAR, &st) == 0) {
762
		if (keyname == NULL)
763
			snprintf(cmd, sizeof(cmd), "%s -zcf %s.tgz -C %s .",
764
			    PATH_TAR, oname, ca->sslpath);
765
		else
766
			snprintf(cmd, sizeof(cmd), "%s -zcf %s.tgz -C %s .",
767
			    PATH_TAR, oname, p);
768
		system(cmd);
769
		snprintf(src, sizeof(src), "%s.tgz", oname);
770
		if (realpath(src, dst) != NULL)
771
			printf("exported files in %s\n", dst);
772
	}
773
774
	if (stat(PATH_ZIP, &st) == 0) {
775
		dexp = opendir(EXPDIR);
776
		if (dexp) {
777
			while ((de = readdir(dexp)) != NULL) {
778
				if (!strcmp(de->d_name, ".") ||
779
				    !strcmp(de->d_name, ".."))
780
					continue;
781
				snprintf(src, sizeof(src), "%s/%s", EXPDIR,
782
				    de->d_name);
783
				snprintf(dst, sizeof(dst), "%s/export/%s", p,
784
				    de->d_name);
785
				fcopy(src, dst, 0644);
786
			}
787
			closedir(dexp);
788
		}
789
790
		snprintf(dst, sizeof(dst), "%s/export", p);
791
		if (getcwd(src, sizeof(src)) == NULL)
792
			err(1, "could not get cwd");
793
794
		if (chdir(dst) == -1)
795
			err(1, "could not change %s", dst);
796
797
		snprintf(dst, sizeof(dst), "%s/%s.zip", src, oname);
798
		snprintf(cmd, sizeof(cmd), "%s -qr %s .", PATH_ZIP, dst);
799
		system(cmd);
800
		printf("exported files in %s\n", dst);
801
802
		if (chdir(src) == -1)
803
			err(1, "could not change %s", dst);
804
	}
805
806
	rm_dir(p);
807
808
	return (0);
809
}
810
811
/* create index if it doesn't already exist */
812
void
813
ca_create_index(struct ca *ca)
814
{
815
	struct stat	 st;
816
	int		 fd;
817
818
	if (snprintf(ca->index, sizeof(ca->index), "%s/index.txt",
819
	    ca->sslpath) < 0)
820
		err(1, "snprintf");
821
	if (stat(ca->index, &st) != 0) {
822
		if  (errno == ENOENT) {
823
			if ((fd = open(ca->index, O_WRONLY | O_CREAT, 0644))
824
			    == -1)
825
				err(1, "could not create file %s", ca->index);
826
			close(fd);
827
		} else
828
			err(1, "could not access %s", ca->index);
829
	}
830
831
	if (snprintf(ca->serial, sizeof(ca->serial), "%s/serial.txt",
832
	    ca->sslpath) < 0)
833
		err(1, "snprintf");
834
	if (stat(ca->serial, &st) != 0) {
835
		if  (errno == ENOENT) {
836
			if ((fd = open(ca->serial, O_WRONLY | O_CREAT, 0644))
837
			    == -1)
838
				err(1, "could not create file %s", ca->serial);
839
			/* serial file must be created with a number */
840
			if (write(fd, "01\n", 3) != 3)
841
				err(1, "write %s", ca->serial);
842
			close(fd);
843
		} else
844
			err(1, "could not access %s", ca->serial);
845
	}
846
}
847
848
int
849
ca_revoke(struct ca *ca, char *keyname)
850
{
851
	struct stat	 st;
852
	char		 cmd[PATH_MAX * 2];
853
	char		 path[PATH_MAX];
854
855
	if (keyname) {
856
		snprintf(path, sizeof(path), "%s/%s.crt",
857
		    ca->sslpath, keyname);
858
		if (stat(path, &st) != 0) {
859
			warn("Problem with certificate for '%s'", keyname);
860
			return (1);
861
		}
862
	}
863
864
	ca_create_index(ca);
865
866
	ca_setenv("$ENV::CADB", ca->index);
867
	ca_setenv("$ENV::CASERIAL", ca->serial);
868
	if (keyname)
869
		ca_setenv("$ENV::REQ_EXT", "");
870
871
	ca_setcnf(ca, "ca-revoke");
872
873
	if (keyname) {
874
		snprintf(cmd, sizeof(cmd),
875
		    "%s ca %s-config %s -keyfile %s/private/ca.key"
876
		    " -passin file:%s"
877
		    " -cert %s/ca.crt"
878
		    " -revoke %s/%s.crt",
879
		    PATH_OPENSSL, ca->batch, ca->sslcnf,
880
		    ca->sslpath, ca->passfile, ca->sslpath, ca->sslpath, keyname);
881
		system(cmd);
882
	}
883
884
	snprintf(cmd, sizeof(cmd),
885
	    "%s ca %s-config %s -keyfile %s/private/ca.key"
886
	    " -passin file:%s"
887
	    " -gencrl"
888
	    " -cert %s/ca.crt"
889
	    " -crldays 365"
890
	    " -out %s/ca.crl",
891
	    PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath,
892
	    ca->passfile, ca->sslpath, ca->sslpath);
893
	system(cmd);
894
895
	return (0);
896
}
897
898
void
899
ca_clrenv(void)
900
{
901
	int	 i;
902
	for (i = 0; ca_env[i][0] != NULL; i++) {
903
		free(ca_env[i][1]);
904
		ca_env[i][1] = NULL;
905
	}
906
}
907
908
void
909
ca_setenv(const char *key, const char *value)
910
{
911
	int	 i;
912
	char	*p = NULL;
913
914
	for (i = 0; ca_env[i][0] != NULL; i++) {
915
		if (strcmp(ca_env[i][0], key) == 0) {
916
			if (ca_env[i][1] != NULL)
917
				errx(1, "env %s already set: %s", key, value);
918
			p = strdup(value);
919
			if (p == NULL)
920
				err(1, NULL);
921
			ca_env[i][1] = p;
922
			return;
923
		}
924
	}
925
	errx(1, "env %s invalid", key);
926
}
927
928
void
929
ca_setcnf(struct ca *ca, const char *keyname)
930
{
931
	struct stat	 st;
932
	const char	*extcnf, *sslcnf;
933
934
	if (stat(IKECA_CNF, &st) == 0) {
935
		extcnf = IKECA_CNF;
936
		sslcnf = IKECA_CNF;
937
	} else {
938
		extcnf = X509_CNF;
939
		sslcnf = SSL_CNF;
940
	}
941
942
	snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf",
943
	    ca->sslpath, keyname);
944
	snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf",
945
	    ca->sslpath, keyname);
946
947
	fcopy_env(extcnf, ca->extcnf, 0400);
948
	fcopy_env(sslcnf, ca->sslcnf, 0400);
949
}
950
951
struct ca *
952
ca_setup(char *caname, int create, int quiet, char *pass)
953
{
954
	struct stat	 st;
955
	struct ca	*ca;
956
	char		 path[PATH_MAX];
957
958
	if (stat(PATH_OPENSSL, &st) == -1)
959
		err(1, "openssl binary not available");
960
961
	if ((ca = calloc(1, sizeof(struct ca))) == NULL)
962
		err(1, "calloc");
963
964
	ca->caname = strdup(caname);
965
	snprintf(ca->sslpath, sizeof(ca->sslpath), SSLDIR "/%s", caname);
966
	strlcpy(ca->passfile, ca->sslpath, sizeof(ca->passfile));
967
	strlcat(ca->passfile, "/ikeca.passwd", sizeof(ca->passfile));
968
969
	if (quiet)
970
		strlcpy(ca->batch, "-batch ", sizeof(ca->batch));
971
972
	if (create == 0 && stat(ca->sslpath, &st) == -1) {
973
		free(ca->caname);
974
		free(ca);
975
		errx(1, "CA '%s' does not exist", caname);
976
	}
977
978
	strlcpy(path, ca->sslpath, sizeof(path));
979
	if (mkdir(path, 0777) == -1 && errno != EEXIST)
980
		err(1, "failed to create dir %s", path);
981
	strlcat(path, "/private", sizeof(path));
982
	if (mkdir(path, 0700) == -1 && errno != EEXIST)
983
		err(1, "failed to create dir %s", path);
984
985
	if (create && stat(ca->passfile, &st) == -1 && errno == ENOENT)
986
		ca_newpass(ca->passfile, pass);
987
988
	return (ca);
989
}