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