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 *);
 

Reply via email to