Module Name: src
Committed By: riastradh
Date: Fri Aug 12 10:49:35 UTC 2022
Modified Files:
src/sbin/cgdconfig: cgdconfig.8 cgdconfig.c params.c params.h
Log Message:
cgdconfig(8): Add support for generating shared-key parameters files.
Usage model:
- Generate a parameters file that supports sharing its main key:
cgdconfig -g -S -o /etc/cgd/wd0e -V gpt adiantum
- Make another parameters file that uses the same shared main key but
derives an independent subkey from it:
cgdconfig -g -S -P /etc/cgd/wd0e -o /etc/cgd/ld1e \
-V disklabel aes-cbc 256
To generate a diff of this commit:
cvs rdiff -u -r1.55 -r1.56 src/sbin/cgdconfig/cgdconfig.8
cvs rdiff -u -r1.56 -r1.57 src/sbin/cgdconfig/cgdconfig.c
cvs rdiff -u -r1.33 -r1.34 src/sbin/cgdconfig/params.c
cvs rdiff -u -r1.13 -r1.14 src/sbin/cgdconfig/params.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sbin/cgdconfig/cgdconfig.8
diff -u src/sbin/cgdconfig/cgdconfig.8:1.55 src/sbin/cgdconfig/cgdconfig.8:1.56
--- src/sbin/cgdconfig/cgdconfig.8:1.55 Fri Aug 12 10:49:17 2022
+++ src/sbin/cgdconfig/cgdconfig.8 Fri Aug 12 10:49:35 2022
@@ -1,4 +1,4 @@
-.\" $NetBSD: cgdconfig.8,v 1.55 2022/08/12 10:49:17 riastradh Exp $
+.\" $NetBSD: cgdconfig.8,v 1.56 2022/08/12 10:49:35 riastradh Exp $
.\"
.\" Copyright (c) 2002, The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -52,11 +52,12 @@
.Ar paramsfile
.Nm
.Fl g
-.Op Fl v
+.Op Fl Sv
.Op Fl V Ar vmeth
.Op Fl i Ar ivmeth
.Op Fl k Ar kgmeth
.Op Fl o Ar outfile
+.Op Fl P Ar paramsfile
.Ar alg
.Op Ar keylen
.Nm
@@ -138,6 +139,13 @@ store it in
If
.Fl o
is not given, any paramsfile content is written to standard output.
+.It Fl P Ar paramsfile
+With the
+.Fl S
+option for the
+.Fl g
+action, specify a parameters file with a shared key to reuse for
+deriving this one as a subkey.
.It Fl p
Read all passphrases from stdin rather than
.Pa /dev/tty .
@@ -147,6 +155,15 @@ are prompted.
If this flag is specified then verification errors will cause the device
in question to be unconfigured rather than prompting for the passphrase
again.
+.It Fl S
+When generating a parameters file with
+.Fl g ,
+arrange to use a subkey of a shared key.
+If
+.Fl P Ar paramsfile
+is also specified, reuse the shared key of
+.Ar paramsfile ;
+otherwise a new one will be generated.
.It Fl s
Read the key (nb: not the passphrase) from stdin.
.It Fl T
@@ -485,6 +502,19 @@ parameters file:
new file's passphrase:
.Ed
.Pp
+To create parameters files for three disks with subkeys derived from a
+shared password-based key:
+.Bd -literal
+ # cgdconfig -g -S -k argon2id -o /etc/cgd/wd0 -V gpt adiantum
+ # cgdconfig -g -S -P /etc/cgd/wd0 -o /etc/cgd/ld1 \e
+ -V disklabel aes-cbc 256
+.Ed
+.Pp
+Listing these in the same
+.Pa /etc/cgd/cgd.conf
+will allow you to enter a password once to decrypt both disks with
+.Cm cgdconfig -C .
+.Pp
To configure a cgd that uses aes-cbc with a 192 bit key that it
reads from stdin:
.Bd -literal
Index: src/sbin/cgdconfig/cgdconfig.c
diff -u src/sbin/cgdconfig/cgdconfig.c:1.56 src/sbin/cgdconfig/cgdconfig.c:1.57
--- src/sbin/cgdconfig/cgdconfig.c:1.56 Fri Aug 12 10:49:17 2022
+++ src/sbin/cgdconfig/cgdconfig.c Fri Aug 12 10:49:35 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: cgdconfig.c,v 1.56 2022/08/12 10:49:17 riastradh Exp $ */
+/* $NetBSD: cgdconfig.c,v 1.57 2022/08/12 10:49:35 riastradh Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 2002, 2003\
The NetBSD Foundation, Inc. All rights reserved.");
-__RCSID("$NetBSD: cgdconfig.c,v 1.56 2022/08/12 10:49:17 riastradh Exp $");
+__RCSID("$NetBSD: cgdconfig.c,v 1.57 2022/08/12 10:49:35 riastradh Exp $");
#endif
#ifdef HAVE_ARGON2
@@ -100,6 +100,10 @@ enum action {
int nflag = 0;
+/* if Sflag is set, generate shared keys */
+
+int Sflag = 0;
+
/* if pflag is set to PFLAG_STDIN read from stdin rather than getpass(3) */
#define PFLAG_GETPASS 0x01
@@ -123,7 +127,8 @@ LIST_HEAD(, sharedkey) sharedkeys;
static int configure(int, char **, struct params *, int);
static int configure_stdin(struct params *, int argc, char **);
-static int generate(struct params *, int, char **, const char *);
+static int generate(struct params *, int, char **, const char *,
+ const char *);
static int generate_convert(struct params *, int, char **, const char *);
static int unconfigure(int, char **, struct params *, int);
static int do_all(const char *, int, char **,
@@ -177,8 +182,8 @@ usage(void)
getprogname());
(void)fprintf(stderr, " %s -G [-enpv] [-i ivmeth] [-k kgmeth] "
"[-o outfile] paramsfile\n", getprogname());
- (void)fprintf(stderr, " %s -g [-v] [-i ivmeth] [-k kgmeth] "
- "[-o outfile] alg [keylen]\n", getprogname());
+ (void)fprintf(stderr, " %s -g [-Sv] [-i ivmeth] [-k kgmeth] "
+ "[-P paramsfile] [-o outfile] alg [keylen]\n", getprogname());
(void)fprintf(stderr, " %s -l [-v[v]] [cgd]\n", getprogname());
(void)fprintf(stderr, " %s -s [-nv] [-i ivmeth] cgd dev alg "
"[keylen]\n", getprogname());
@@ -230,6 +235,7 @@ main(int argc, char **argv)
int ch;
const char *cfile = NULL;
const char *outfile = NULL;
+ const char *Pfile = NULL;
setprogname(*argv);
if (hkdf_hmac_sha256_selftest())
@@ -240,7 +246,7 @@ main(int argc, char **argv)
p = params_new();
kg = NULL;
- while ((ch = getopt(argc, argv, "CGTUV:b:ef:gi:k:lno:sptuv")) != -1)
+ while ((ch = getopt(argc, argv, "CGP:STUV:b:ef:gi:k:lno:sptuv")) != -1)
switch (ch) {
case 'C':
set_action(&action, ACTION_CONFIGALL);
@@ -248,6 +254,14 @@ main(int argc, char **argv)
case 'G':
set_action(&action, ACTION_GENERATE_CONVERT);
break;
+ case 'P':
+ if (Pfile)
+ usage();
+ Pfile = estrdup(optarg);
+ break;
+ case 'S':
+ Sflag = 1;
+ break;
case 'T':
set_action(&action, ACTION_PRINTALLKEYS);
break;
@@ -336,6 +350,17 @@ main(int argc, char **argv)
err(1, "init failed");
/* validate the consistency of the arguments */
+ if (Pfile != NULL && action != ACTION_GENERATE) {
+ warnx("-P is only for use with -g action");
+ usage();
+ }
+ if (Pfile != NULL && !Sflag) {
+ warnx("-P only makes sense with -S flag");
+ }
+ if (Sflag && action != ACTION_GENERATE) {
+ warnx("-S is only for use with -g action");
+ usage();
+ }
switch (action) {
case ACTION_DEFAULT: /* ACTION_CONFIGURE is the default */
@@ -344,7 +369,7 @@ main(int argc, char **argv)
case ACTION_UNCONFIGURE:
return unconfigure(argc, argv, NULL, CONFIG_FLAGS_FROMMAIN);
case ACTION_GENERATE:
- return generate(p, argc, argv, outfile);
+ return generate(p, argc, argv, outfile, Pfile);
case ACTION_GENERATE_CONVERT:
return generate_convert(p, argc, argv, outfile);
case ACTION_CONFIGALL:
@@ -1197,7 +1222,8 @@ verify_reenter(struct params *p)
}
static int
-generate(struct params *p, int argc, char **argv, const char *outfile)
+generate(struct params *p, int argc, char **argv, const char *outfile,
+ const char *Pfile)
{
int ret;
@@ -1219,15 +1245,43 @@ generate(struct params *p, int argc, cha
if (ret)
return ret;
- if (!p->keygen) {
- p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
- if (!p->keygen)
+ if (Pfile) {
+ struct params *pp;
+
+ pp = params_cget(Pfile);
+ if (pp == NULL)
+ return -1;
+ if (!params_verify(pp)) {
+ params_free(pp);
+ warnx("invalid parameters file \"%s\"", Pfile);
+ return -1;
+ }
+ p = params_combine(pp, p);
+ keygen_stripstored(&p->keygen);
+ if (!p->keygen) {
+ warnx("no keygen in parameters file \"%s\"", Pfile);
return -1;
+ }
+ } else {
+ if (!p->keygen) {
+ p->keygen = keygen_generate(KEYGEN_PKCS5_PBKDF2_SHA1);
+ if (!p->keygen)
+ return -1;
+ }
+
+ if (keygen_filldefaults(p->keygen, p->keylen)) {
+ warnx("Failed to generate defaults for keygen");
+ return -1;
+ }
}
- if (keygen_filldefaults(p->keygen, p->keylen)) {
- warnx("Failed to generate defaults for keygen");
- return -1;
+ if (Sflag) {
+ if (Pfile)
+ ret = keygen_tweakshared(p->keygen);
+ else
+ ret = keygen_makeshared(p->keygen);
+ if (ret)
+ return ret;
}
if (!params_verify(p)) {
Index: src/sbin/cgdconfig/params.c
diff -u src/sbin/cgdconfig/params.c:1.33 src/sbin/cgdconfig/params.c:1.34
--- src/sbin/cgdconfig/params.c:1.33 Fri Aug 12 10:49:17 2022
+++ src/sbin/cgdconfig/params.c Fri Aug 12 10:49:35 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: params.c,v 1.33 2022/08/12 10:49:17 riastradh Exp $ */
+/* $NetBSD: params.c,v 1.34 2022/08/12 10:49:35 riastradh Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: params.c,v 1.33 2022/08/12 10:49:17 riastradh Exp $");
+__RCSID("$NetBSD: params.c,v 1.34 2022/08/12 10:49:35 riastradh Exp $");
#endif
#include <sys/types.h>
@@ -46,6 +46,7 @@ __RCSID("$NetBSD: params.c,v 1.33 2022/0
#include <stdlib.h>
#include <string.h>
#include <util.h>
+#include <uuid.h>
#ifdef HAVE_ARGON2
#include <argon2.h>
@@ -524,6 +525,122 @@ keygen_filldefaults(struct keygen *kg, s
return keygen_filldefaults(kg->next, keylen);
}
+/*
+ * Strip the storedkey entries in preparation for inserting a shared
+ * clause with a newly generated info string to derive this key from
+ * KDF. The result is that the key generated here is independent of
+ * whatever storedkeys were involved in the old one, so there is no
+ * need to keep them around,
+ */
+void
+keygen_stripstored(struct keygen **kgp)
+{
+ struct keygen *kg, *to_free = NULL;
+
+ while ((kg = *kgp) != NULL) {
+ if (kg->kg_method == KEYGEN_STOREDKEY) {
+ *kgp = kg->next;
+ kg->next = to_free;
+ to_free = kg;
+ } else {
+ kgp = &kg->next;
+ }
+ }
+ keygen_free(to_free);
+}
+
+int
+keygen_makeshared(struct keygen *kg0)
+{
+ struct keygen *kg;
+
+ for (kg = kg0; kg != NULL; kg = kg->next) {
+ switch (kg->kg_method) {
+ case KEYGEN_RANDOMKEY:
+ case KEYGEN_URANDOMKEY:
+ warnx("(u)randomkey keygen cannot be shared");
+ return -1;
+ case KEYGEN_SHELL_CMD:
+#ifdef HAVE_ARGON2
+ case KEYGEN_ARGON2ID:
+#endif
+ case KEYGEN_PKCS5_PBKDF2_OLD:
+ case KEYGEN_PKCS5_PBKDF2_SHA1:
+ break;
+ case KEYGEN_STOREDKEY:
+ warnx("storedkey does not make sense as shared");
+ return -1;
+ default:
+ return -1;
+ }
+ if (kg->kg_sharedid != NULL) {
+ warnx("keygen already shared");
+ return -1;
+ }
+ }
+ for (kg = kg0; kg != NULL; kg = kg->next) {
+ struct uuid id;
+ char *idstr;
+ uint32_t status;
+
+ if (uuidgen(&id, 1) == -1) {
+ warn("uuidgen");
+ return -1;
+ }
+ uuid_to_string(&id, &idstr, &status);
+ if (status != uuid_s_ok) {
+ warnx("uuid_to_string: %"PRIu32, status);
+ return -1;
+ }
+
+ kg->kg_sharedid = string_fromcharstar(idstr);
+ kg->kg_sharedalg = SHARED_ALG_HKDF_HMAC_SHA256;
+ kg->kg_sharedlen = 8*SHA256_DIGEST_LENGTH;
+ kg->kg_sharedinfo = bits_getrandombits(DEFAULT_SALTLEN, 0);
+
+ free(idstr);
+ }
+ return 0;
+}
+
+int
+keygen_tweakshared(struct keygen *kg0)
+{
+ struct keygen *kg;
+
+ for (kg = kg0; kg != NULL; kg = kg->next) {
+ switch (kg->kg_method) {
+ case KEYGEN_RANDOMKEY:
+ case KEYGEN_URANDOMKEY:
+ warnx("(u)randomkey keygen cannot be shared");
+ return -1;
+ case KEYGEN_SHELL_CMD:
+#ifdef HAVE_ARGON2
+ case KEYGEN_ARGON2ID:
+#endif
+ case KEYGEN_PKCS5_PBKDF2_OLD:
+ case KEYGEN_PKCS5_PBKDF2_SHA1:
+ break;
+ case KEYGEN_STOREDKEY:
+ warnx("storedkey does not make sense as shared");
+ return -1;
+ default:
+ return -1;
+ }
+ if (kg->kg_sharedid == NULL) {
+ warnx("keygen not shared");
+ return -1;
+ }
+ }
+ for (kg = kg0; kg != NULL; kg = kg->next) {
+ if (kg->kg_method == KEYGEN_STOREDKEY)
+ continue;
+ bits_free(kg->kg_sharedinfo);
+ kg->kg_sharedinfo = bits_getrandombits(DEFAULT_SALTLEN, 0);
+ }
+ return 0;
+}
+
struct keygen *
keygen_combine(struct keygen *kg1, struct keygen *kg2)
{
Index: src/sbin/cgdconfig/params.h
diff -u src/sbin/cgdconfig/params.h:1.13 src/sbin/cgdconfig/params.h:1.14
--- src/sbin/cgdconfig/params.h:1.13 Fri Aug 12 10:49:17 2022
+++ src/sbin/cgdconfig/params.h Fri Aug 12 10:49:35 2022
@@ -1,4 +1,4 @@
-/* $NetBSD: params.h,v 1.13 2022/08/12 10:49:17 riastradh Exp $ */
+/* $NetBSD: params.h,v 1.14 2022/08/12 10:49:35 riastradh Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@@ -112,6 +112,9 @@ struct keygen *keygen_new(void);
void keygen_free(struct keygen *);
int keygen_filldefaults(struct keygen *, size_t);
+void keygen_stripstored(struct keygen **);
+int keygen_makeshared(struct keygen *);
+int keygen_tweakshared(struct keygen *);
int keygen_verify(const struct keygen *);
void keygen_addlist(struct keygen **, struct keygen *);