On Fri, Nov 06, 2015 at 12:24:30AM -0500, Toyam Cox wrote:
> I'm running 5.8-release.
ikectl ca in 5.8 is non-functional as LibreSSL removed support for
environment variables in openssl cnf files and this was not
noticed/fixed until after 5.8.
Here is a patch against 5.8 that adds the changes to cope with that.
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/ikectl/Makefile,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -p -r1.3 -r1.4
--- Makefile 18 Jan 2014 05:54:51 -0000 1.3
+++ Makefile 19 Aug 2015 12:25:59 -0000 1.4
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.3 2014/01/18 05:54:51 martynas Exp $
+# $OpenBSD: Makefile,v 1.4 2015/08/19 12:25:59 reyk Exp $
.PATH: ${.CURDIR}/../../sbin/iked
PROG= ikectl
-SRCS= log.c ikeca.c ikectl.c parser.c
+SRCS= log.c ikeca.c ikectl.c parser.c util.c
MAN= ikectl.8
Index: ikeca.c
===================================================================
RCS file: /cvs/src/usr.sbin/ikectl/ikeca.c,v
retrieving revision 1.30
retrieving revision 1.33
diff -u -p -r1.30 -r1.33
--- ikeca.c 16 Jan 2015 06:40:17 -0000 1.30
+++ ikeca.c 19 Aug 2015 12:25:59 -0000 1.33
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikeca.c,v 1.30 2015/01/16 06:40:17 deraadt Exp $ */
+/* $OpenBSD: ikeca.c,v 1.33 2015/08/19 12:25:59 reyk Exp $ */
/*
* Copyright (c) 2010 Jonathan Gray <[email protected]>
@@ -82,13 +82,39 @@ struct {
{ "/private", 0700 }
};
-int ca_sign(struct ca *, char *, int, char *);
+/* explicitly list allowed variables */
+const char *ca_env[][2] = {
+ { "$ENV::CADB", NULL },
+ { "$ENV::CERTFQDN", NULL },
+ { "$ENV::CERTIP", NULL },
+ { "$ENV::CERTPATHLEN", NULL },
+ { "$ENV::CERTUSAGE", NULL },
+ { "$ENV::CERT_C", NULL },
+ { "$ENV::CERT_CN", NULL },
+ { "$ENV::CERT_EMAIL", NULL },
+ { "$ENV::CERT_L", NULL },
+ { "$ENV::CERT_O", NULL },
+ { "$ENV::CERT_OU", NULL },
+ { "$ENV::CERT_ST", NULL },
+ { "$ENV::EXTCERTUSAGE", NULL },
+ { "$ENV::NSCERTTYPE", NULL },
+ { NULL }
+};
+
+int ca_sign(struct ca *, char *, int);
int ca_request(struct ca *, char *);
int ca_newpass(char *, char *);
char * ca_readpass(char *, size_t *);
int fcopy(char *, char *, mode_t);
+int fcopy_env(const char *, const char *, mode_t);
int rm_dir(char *);
int ca_hier(char *);
+void ca_setenv(const char *, const char *);
+void ca_clrenv(void);
+void ca_setcnf(struct ca *, const char *);
+
+/* util.c */
+int expand_string(char *, size_t, const char *, const char *);
int
ca_delete(struct ca *ca)
@@ -173,10 +199,13 @@ ca_request(struct ca *ca, char *keyname)
char cmd[PATH_MAX * 2];
char path[PATH_MAX];
+ ca_setenv("$ENV::CERT_CN", keyname);
+ ca_setcnf(ca, keyname);
+
snprintf(path, sizeof(path), "%s/private/%s.csr", ca->sslpath, keyname);
- snprintf(cmd, sizeof(cmd), "env CERT_CN=%s %s req %s-new"
+ snprintf(cmd, sizeof(cmd), "%s req %s-new"
" -key %s/private/%s.key -out %s -config %s",
- keyname, PATH_OPENSSL, ca->batch, ca->sslpath, keyname,
+ PATH_OPENSSL, ca->batch, ca->sslpath, keyname,
path, ca->sslcnf);
system(cmd);
@@ -186,40 +215,40 @@ ca_request(struct ca *ca, char *keyname)
}
int
-ca_sign(struct ca *ca, char *keyname, int type, char *envargs)
+ca_sign(struct ca *ca, char *keyname, int type)
{
char cmd[PATH_MAX * 2];
char hostname[HOST_NAME_MAX+1];
char name[128];
+ const char *extensions = NULL;
strlcpy(name, keyname, sizeof(name));
- if (envargs == NULL)
- envargs = "";
-
if (type == HOST_IPADDR) {
- snprintf(cmd, sizeof(cmd), "env CERTIP=%s%s %s x509 -req"
- " -days 365 -in %s/private/%s.csr"
- " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial"
- " -extfile %s -extensions x509v3_IPAddr -out %s/%s.crt"
- " -passin file:%s", name, envargs, PATH_OPENSSL,
- ca->sslpath, keyname, ca->sslpath, ca->sslpath,
- ca->extcnf, ca->sslpath, keyname, ca->passfile);
+ ca_setenv("$ENV::CERTIP", name);
+ extensions = "x509v3_IPAddr";
} else if (type == HOST_FQDN) {
if (!strcmp(keyname, "local")) {
if (gethostname(hostname, sizeof(hostname)))
err(1, "gethostname");
strlcpy(name, hostname, sizeof(name));
}
- snprintf(cmd, sizeof(cmd), "env CERTFQDN=%s%s %s x509 -req"
- " -days 365 -in %s/private/%s.csr"
- " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial"
- " -extfile %s -extensions x509v3_FQDN -out %s/%s.crt"
- " -passin file:%s", name, envargs, PATH_OPENSSL,
- ca->sslpath, keyname, ca->sslpath, ca->sslpath,
- ca->extcnf, ca->sslpath, keyname, ca->passfile);
- } else
- err(1, "unknown host type %d", type);
+ ca_setenv("$ENV::CERTFQDN", name);
+ extensions = "x509v3_FQDN";
+ } else {
+ errx(1, "unknown host type %d", type);
+ }
+
+ ca_setcnf(ca, keyname);
+
+ snprintf(cmd, sizeof(cmd), "%s x509 -req"
+ " -days 365 -in %s/private/%s.csr"
+ " -CA %s/ca.crt -CAkey %s/private/ca.key -CAcreateserial"
+ " -extfile %s -extensions %s -out %s/%s.crt"
+ " -passin file:%s",
+ PATH_OPENSSL,
+ ca->sslpath, keyname, ca->sslpath, ca->sslpath,
+ ca->extcnf, extensions, ca->sslpath, keyname, ca->passfile);
system(cmd);
@@ -229,16 +258,20 @@ ca_sign(struct ca *ca, char *keyname, in
int
ca_certificate(struct ca *ca, char *keyname, int type, int action)
{
- char *envargs = "";
+ ca_clrenv();
switch (action) {
case CA_SERVER:
- envargs = " EXTCERTUSAGE=serverAuth NSCERTTYPE=server"
- " CERTUSAGE=digitalSignature,keyEncipherment";
+ ca_setenv("$ENV::EXTCERTUSAGE", "serverAuth");
+ ca_setenv("$ENV::NSCERTTYPE", "server");
+ ca_setenv("$ENV::CERTUSAGE",
+ "digitalSignature,keyEncipherment");
break;
case CA_CLIENT:
- envargs = " EXTCERTUSAGE=clientAuth NSCERTTYPE=client"
- " CERTUSAGE=digitalSignature,keyAgreement";
+ ca_setenv("$ENV::EXTCERTUSAGE", "clientAuth");
+ ca_setenv("$ENV::NSCERTTYPE", "client");
+ ca_setenv("$ENV::CERTUSAGE",
+ "digitalSignature,keyAgreement");
break;
default:
break;
@@ -246,7 +279,7 @@ ca_certificate(struct ca *ca, char *keyn
ca_key_create(ca, keyname);
ca_request(ca, keyname);
- ca_sign(ca, keyname, type, envargs);
+ ca_sign(ca, keyname, type);
return (0);
}
@@ -352,6 +385,8 @@ ca_create(struct ca *ca)
char cmd[PATH_MAX * 2];
char path[PATH_MAX];
+ ca_clrenv();
+
snprintf(path, sizeof(path), "%s/private/ca.key", ca->sslpath);
snprintf(cmd, sizeof(cmd), "%s genrsa -aes256 -out"
" %s -passout file:%s 2048", PATH_OPENSSL,
@@ -359,8 +394,11 @@ ca_create(struct ca *ca)
system(cmd);
chmod(path, 0600);
+ ca_setenv("$ENV::CERT_CN", "VPN CA");
+ ca_setcnf(ca, "ca");
+
snprintf(path, sizeof(path), "%s/private/ca.csr", ca->sslpath);
- snprintf(cmd, sizeof(cmd), "env CERT_CN='VPN CA' %s req %s-new"
+ snprintf(cmd, sizeof(cmd), "%s req %s-new"
" -key %s/private/ca.key"
" -config %s -out %s -passin file:%s", PATH_OPENSSL,
ca->batch, ca->sslpath, ca->sslcnf, path, ca->passfile);
@@ -489,6 +527,47 @@ fcopy(char *src, char *dst, mode_t mode)
}
int
+fcopy_env(const char *src, const char *dst, mode_t mode)
+{
+ int ofd = -1, i;
+ u_int8_t buf[BUFSIZ];
+ ssize_t r = -1, len;
+ FILE *ifp = NULL;
+ int saved_errno;
+
+ if ((ifp = fopen(src, "r")) == NULL)
+ err(1, "fopen %s", src);
+
+ if ((ofd = open(dst, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1)
+ goto done;
+
+ while (fgets(buf, sizeof(buf), ifp) != NULL) {
+ for (i = 0; ca_env[i][0] != NULL; i++) {
+ if (ca_env[i][1] == NULL)
+ continue;
+ if (expand_string(buf, sizeof(buf),
+ ca_env[i][0], ca_env[i][1]) == -1)
+ errx(1, "env %s value too long", ca_env[i][0]);
+ }
+ len = strlen(buf);
+ if (write(ofd, buf, len) != len)
+ goto done;
+ }
+
+ r = 0;
+
+ done:
+ saved_errno = errno;
+ close(ofd);
+ if (ifp != NULL)
+ fclose(ifp);
+ if (r == -1)
+ errc(1, saved_errno, "open %s", dst);
+
+ return (0);
+}
+
+int
rm_dir(char *path)
{
FTS *fts;
@@ -561,7 +640,7 @@ ca_export(struct ca *ca, char *keyname,
if (keyname != NULL) {
if (strlcpy(oname, keyname, sizeof(oname)) >= sizeof(oname))
- err(1, "name too long");
+ errx(1, "name too long");
} else {
strlcpy(oname, "ca", sizeof(oname));
}
@@ -683,7 +762,7 @@ ca_export(struct ca *ca, char *keyname,
de->d_name);
snprintf(dst, sizeof(dst), "%s/export/%s", p,
de->d_name);
- fcopy(src, dst, 644);
+ fcopy(src, dst, 0644);
}
closedir(dexp);
}
@@ -742,6 +821,7 @@ ca_revoke(struct ca *ca, char *keyname)
struct stat st;
char cmd[PATH_MAX * 2];
char path[PATH_MAX];
+ char cadb[PATH_MAX];
int fd;
char *pass;
size_t len;
@@ -758,7 +838,7 @@ ca_revoke(struct ca *ca, char *keyname)
snprintf(path, sizeof(path), "%s/ikeca.passwd", ca->sslpath);
pass = ca_readpass(path, &len);
if (pass == NULL)
- err(1, "could not open passphrase file");
+ errx(1, "could not open passphrase file");
/* create index if it doesn't already exist */
snprintf(path, sizeof(path), "%s/index.txt", ca->sslpath);
@@ -771,27 +851,31 @@ ca_revoke(struct ca *ca, char *keyname)
err(1, "could not access %s", path);
}
+ snprintf(cadb, sizeof(cadb), "%s/index.txt", ca->sslpath);
+ ca_setenv("$ENV::CADB", cadb);
+ ca_setcnf(ca, "ca-revoke");
+
if (keyname) {
- snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' "
- " %s ca %s-config %s -keyfile %s/private/ca.key"
+ snprintf(cmd, sizeof(cmd),
+ "%s ca %s-config %s -keyfile %s/private/ca.key"
" -key %s"
" -cert %s/ca.crt"
" -md sha1"
" -revoke %s/%s.crt",
- ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf,
+ PATH_OPENSSL, ca->batch, ca->sslcnf,
ca->sslpath, pass, ca->sslpath, ca->sslpath, keyname);
system(cmd);
}
- snprintf(cmd, sizeof(cmd), "env CADB='%s/index.txt' "
- " %s ca %s-config %s -keyfile %s/private/ca.key"
+ snprintf(cmd, sizeof(cmd),
+ "%s ca %s-config %s -keyfile %s/private/ca.key"
" -key %s"
" -gencrl"
" -cert %s/ca.crt"
" -md sha1"
" -crldays 365"
" -out %s/ca.crl",
- ca->sslpath, PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath,
+ PATH_OPENSSL, ca->batch, ca->sslcnf, ca->sslpath,
pass, ca->sslpath, ca->sslpath);
system(cmd);
@@ -801,6 +885,53 @@ ca_revoke(struct ca *ca, char *keyname)
return (0);
}
+void
+ca_clrenv(void)
+{
+ int i;
+ for (i = 0; ca_env[i][0] != NULL; i++)
+ ca_env[i][1] = NULL;
+}
+
+void
+ca_setenv(const char *key, const char *value)
+{
+ int i;
+
+ for (i = 0; ca_env[i][0] != NULL; i++) {
+ if (strcmp(ca_env[i][0], key) == 0) {
+ if (ca_env[i][1] != NULL)
+ errx(1, "env %s already set: %s", key, value);
+ ca_env[i][1] = value;
+ return;
+ }
+ }
+ errx(1, "env %s invalid", key);
+}
+
+void
+ca_setcnf(struct ca *ca, const char *keyname)
+{
+ struct stat st;
+ const char *extcnf, *sslcnf;
+
+ if (stat(IKECA_CNF, &st) == 0) {
+ extcnf = IKECA_CNF;
+ sslcnf = IKECA_CNF;
+ } else {
+ extcnf = X509_CNF;
+ sslcnf = SSL_CNF;
+ }
+
+ snprintf(ca->extcnf, sizeof(ca->extcnf), "%s/%s-ext.cnf",
+ ca->sslpath, keyname);
+ snprintf(ca->sslcnf, sizeof(ca->sslcnf), "%s/%s-ssl.cnf",
+ ca->sslpath, keyname);
+
+ fcopy_env(extcnf, ca->extcnf, 0400);
+ fcopy_env(sslcnf, ca->sslcnf, 0400);
+}
+
struct ca *
ca_setup(char *caname, int create, int quiet, char *pass)
{
@@ -821,14 +952,6 @@ ca_setup(char *caname, int create, int q
if (quiet)
strlcpy(ca->batch, "-batch ", sizeof(ca->batch));
-
- if (stat(IKECA_CNF, &st) == 0) {
- strlcpy(ca->extcnf, IKECA_CNF, sizeof(ca->extcnf));
- strlcpy(ca->sslcnf, IKECA_CNF, sizeof(ca->sslcnf));
- } else {
- strlcpy(ca->extcnf, X509_CNF, sizeof(ca->extcnf));
- strlcpy(ca->sslcnf, SSL_CNF, sizeof(ca->sslcnf));
- }
if (create == 0 && stat(ca->sslpath, &st) == -1) {
free(ca->caname);