summaryrefslogtreecommitdiff
path: root/usr.sbin/ikectl/ikeca.c
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2015-08-19 12:26:00 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2015-08-19 12:26:00 +0000
commit6819929ef906887516275bfd6c88196e661a44eb (patch)
tree273660f6c4609ed2acfadc47e14659713e9db541 /usr.sbin/ikectl/ikeca.c
parent995509cfe298c1e145989aff18f9e3a161fff5d2 (diff)
Support for overwriting $ENV:: variables in OpenSSL .cnf files from
the environment has been removed in LibreSSL. This was a good step but it unintentionally broke the "ikectl ca" commands. Rework the implementation for copying the .cnf files and expanding the $ENV:: variables ourselves before passing the generated .cnf file to the "openssl" command. Reported and tested by Jona Joachim (thanks!) OK jsg@
Diffstat (limited to 'usr.sbin/ikectl/ikeca.c')
-rw-r--r--usr.sbin/ikectl/ikeca.c211
1 files changed, 167 insertions, 44 deletions
diff --git a/usr.sbin/ikectl/ikeca.c b/usr.sbin/ikectl/ikeca.c
index cb53e7edfe4..7c40eccc22f 100644
--- a/usr.sbin/ikectl/ikeca.c
+++ b/usr.sbin/ikectl/ikeca.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikeca.c,v 1.32 2015/08/15 04:47:28 semarie Exp $ */
+/* $OpenBSD: ikeca.c,v 1.33 2015/08/19 12:25:59 reyk Exp $ */
/*
* Copyright (c) 2010 Jonathan Gray <jsg@openbsd.org>
@@ -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
+ 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, int type, char *envargs)
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 *keyname, int type, int action)
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;
@@ -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;
@@ -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)
{
@@ -822,14 +953,6 @@ ca_setup(char *caname, int create, int quiet, char *pass)
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);
free(ca);