From 1569bcc0b3557876b2e672fed62df3c63e63e2b2 Mon Sep 17 00:00:00 2001 From: nia Date: Mon, 22 Nov 2021 14:34:35 +0000 Subject: [PATCH] cgdconfig(8): Add an argon2id password-based key generation method This provides an extra level of side-channel and cracking resistance compared to the pre-existing pkcs5_pbkdf2/sha1 method used for password-based disk encryption. Several new keygen parameters are supported: memory (integer, in kilobytes) parallelism (integer, usually the number of CPU cores) version (integer, usually 19...) We do our best to calibrate these automatically when the paramsfile is initially generated. lgtm riastradh@ --- .../apache2/argon2/lib/libargon2/Makefile | 23 +++ lib/Makefile | 6 +- sbin/cgdconfig/Makefile | 20 +- sbin/cgdconfig/argon2_utils.c | 182 ++++++++++++++++++ sbin/cgdconfig/argon2_utils.h | 36 ++++ sbin/cgdconfig/cgdconfig.8 | 45 ++++- sbin/cgdconfig/cgdconfig.c | 85 ++++++-- sbin/cgdconfig/cgdlex.l | 7 +- sbin/cgdconfig/cgdparse.y | 9 +- sbin/cgdconfig/params.c | 99 +++++++++- sbin/cgdconfig/params.h | 9 +- 11 files changed, 494 insertions(+), 27 deletions(-) create mode 100644 external/apache2/argon2/lib/libargon2/Makefile create mode 100644 sbin/cgdconfig/argon2_utils.c create mode 100644 sbin/cgdconfig/argon2_utils.h diff --git a/external/apache2/argon2/lib/libargon2/Makefile b/external/apache2/argon2/lib/libargon2/Makefile new file mode 100644 index 000000000000..24d9cd70e9a2 --- /dev/null +++ b/external/apache2/argon2/lib/libargon2/Makefile @@ -0,0 +1,23 @@ +# $NetBSD: Makefile,v 1.4 2021/11/22 14:34:35 nia Exp $ + +LIBISPRIVATE= pic + +.include + +ARGON2DIR= ${NETBSDSRCDIR}/external/apache2/argon2 + +.PATH: ${ARGON2DIR}/dist/phc-winner-argon2/src \ + ${ARGON2DIR}/dist/phc-winner-argon2/src/blake2 \ + ${ARGON2DIR}/dist/phc-winner-argon2/include + +LIB= argon2 +SRCS= argon2.c core.c blake2b.c thread.c encoding.c ref.c + +CFLAGS+= -pthread +CPPFLAGS+= -I${ARGON2DIR}/dist/phc-winner-argon2/include + +.if ${MACHINE} == "vax" +COPTS.blake2b.c+= -O0 +.endif + +.include diff --git a/lib/Makefile b/lib/Makefile index 0cc2abfa266f..3687be34b446 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.292 2021/04/25 23:43:48 christos Exp $ +# $NetBSD: Makefile,v 1.293 2021/11/22 14:34:35 nia Exp $ # from: @(#)Makefile 5.25.1.1 (Berkeley) 5/7/91 .include @@ -54,6 +54,10 @@ SUBDIR+= libskey SUBDIR+= libnvmm .endif +.if (${MKARGON2} != "no") +SUBDIR+= ../external/apache2/argon2/lib/libargon2 +.endif + .if (${MKMDNS} != "no") SUBDIR+= ../external/apache2/mDNSResponder/lib .endif diff --git a/sbin/cgdconfig/Makefile b/sbin/cgdconfig/Makefile index e5f2b5462973..0c0fc56610d7 100644 --- a/sbin/cgdconfig/Makefile +++ b/sbin/cgdconfig/Makefile @@ -1,8 +1,10 @@ -# $NetBSD: Makefile,v 1.15 2016/07/01 22:50:09 christos Exp $ +# $NetBSD: Makefile,v 1.16 2021/11/22 14:34:35 nia Exp $ RUMPPRG=cgdconfig MAN= cgdconfig.8 +.include + SRCS+= cgdconfig.c \ cgdlex.l \ cgdparse.y \ @@ -10,6 +12,10 @@ SRCS+= cgdconfig.c \ params.c \ utils.c +.if ${MKARGON2} != "no" +SRCS+= argon2_utils.c +.endif + CPPFLAGS+= -I${.CURDIR} -I. -DYY_NO_INPUT YHEADER=1 @@ -17,4 +23,16 @@ YHEADER=1 DPADD= ${LIBUTIL} ${LIBCRYPT} ${LIBY} ${LIBL} LDADD= -lutil -lcrypt -ly -ll +.if ${MKARGON2} != "no" +ARGON2DIR= ${NETBSDSRCDIR}/external/apache2/argon2 +ARGON2OBJDIR!= cd ${ARGON2DIR}/lib/libargon2 && ${PRINTOBJDIR} +CPPFLAGS+= -I${NETBSDSRCDIR}/external/apache2/argon2/dist/phc-winner-argon2/include +CPPFLAGS+= -DHAVE_ARGON2 + +PROGDPLIBS+= argon2 ${ARGON2DIR}/lib/libargon2 + +LDADD+= -pthread +DPADD+= ${LIBPTHREAD} +.endif + .include diff --git a/sbin/cgdconfig/argon2_utils.c b/sbin/cgdconfig/argon2_utils.c new file mode 100644 index 000000000000..a990a1c6a806 --- /dev/null +++ b/sbin/cgdconfig/argon2_utils.c @@ -0,0 +1,182 @@ +/* $NetBSD: argon2_utils.c,v 1.1 2021/11/22 14:34:35 nia Exp $ */ +/*- + * Copyright (c) 2021 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nia Alarie. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "argon2_utils.h" + +#ifndef lint +__RCSID("$NetBSD: argon2_utils.c,v 1.1 2021/11/22 14:34:35 nia Exp $"); +#endif + +static size_t +get_cpucount(void) +{ + const int mib[] = { CTL_HW, HW_NCPUONLINE }; + int ncpuonline = 1; + size_t ncpuonline_len = sizeof(ncpuonline); + + if (sysctl(mib, __arraycount(mib), + &ncpuonline, &ncpuonline_len, NULL, 0) == -1) { + return 1; + } + return ncpuonline; +} + +static uint64_t +get_usermem(void) +{ + const int mib[] = { CTL_HW, HW_USERMEM64 }; + uint64_t usermem64 = 0; + size_t usermem64_len = sizeof(usermem64); + struct rlimit rlim; + + if (sysctl(mib, __arraycount(mib), + &usermem64, &usermem64_len, NULL, 0) == -1) { + return 0; + } + + if (getrlimit(RLIMIT_AS, &rlim) == -1) + return usermem64; + if (usermem64 > rlim.rlim_cur && rlim.rlim_cur != RLIM_INFINITY) + usermem64 = rlim.rlim_cur; + return usermem64; /* bytes */ +} + +void +argon2id_calibrate(size_t keylen, size_t saltlen, + size_t *iterations, size_t *memory, size_t *parallelism) +{ + size_t mem = ARGON2_MIN_MEMORY; /* kilobytes */ + size_t time; + const size_t ncpus = get_cpucount(); + const uint64_t usermem = get_usermem(); /* bytes */ + struct timespec tp1, tp2; + struct timespec delta; + unsigned int limit = 0; + uint8_t *key = NULL, *salt = NULL; + uint8_t tmp_pwd[17]; /* just random data for testing */ + int ret = ARGON2_OK; + + key = emalloc(keylen); + salt = emalloc(saltlen); + + arc4random_buf(tmp_pwd, sizeof(tmp_pwd)); + arc4random_buf(salt, saltlen); + + /* 1kb to argon2 per 100kb of user memory */ + mem = usermem / 100000; + + /* 256k: reasonable lower bound from the argon2 test suite */ + if (mem < 256) + mem = 256; + + fprintf(stderr, "calibrating argon2id parameters..."); + + /* Decrease 'mem' if it slows down computation too much */ + + do { + if (clock_gettime(CLOCK_MONOTONIC, &tp1) == -1) + goto error; + if ((ret = argon2_hash(ARGON2_MIN_TIME, mem, ncpus, + tmp_pwd, sizeof(tmp_pwd), + salt, saltlen, + key, keylen, + NULL, 0, + Argon2_id, ARGON2_VERSION_NUMBER)) != ARGON2_OK) { + goto error_argon2; + } + fprintf(stderr, "."); + if (clock_gettime(CLOCK_MONOTONIC, &tp2) == -1) + goto error; + if (timespeccmp(&tp1, &tp2, >)) + goto error_clock; + timespecsub(&tp2, &tp1, &delta); + if (delta.tv_sec >= 1) + mem /= 2; + if (mem < ARGON2_MIN_MEMORY) { + mem = ARGON2_MIN_MEMORY; + break; + } + } while (delta.tv_sec >= 1 && (limit++) < 3); + + delta.tv_sec = 0; + delta.tv_nsec = 0; + + /* Increase 'time' until we reach a second */ + + for (time = ARGON2_MIN_TIME; delta.tv_sec < 1 && + time < ARGON2_MAX_TIME; time <<= 1) { + if (clock_gettime(CLOCK_MONOTONIC, &tp1) == -1) + goto error; + if ((ret = argon2_hash(time, mem, ncpus, + tmp_pwd, sizeof(tmp_pwd), + salt, saltlen, + key, keylen, + NULL, 0, + Argon2_id, ARGON2_VERSION_NUMBER)) != ARGON2_OK) { + goto error_argon2; + } + fprintf(stderr, "."); + if (clock_gettime(CLOCK_MONOTONIC, &tp2) == -1) + goto error; + if (timespeccmp(&tp1, &tp2, >)) + goto error_clock; + timespecsub(&tp2, &tp1, &delta); + } + + if (time > ARGON2_MIN_TIME) + time >>= 1; + + fprintf(stderr, " done\n"); + + free(key); + free(salt); + *iterations = time; + *memory = mem; + *parallelism = ncpus; + return; + +error_argon2: + errx(EXIT_FAILURE, + " failed to calculate Argon2 hash, error code %d", ret); +error_clock: + errx(EXIT_FAILURE, + " failed to calibrate hash parameters: broken monotonic clock?"); +error: + err(EXIT_FAILURE, " failed to calibrate hash parameters"); +} diff --git a/sbin/cgdconfig/argon2_utils.h b/sbin/cgdconfig/argon2_utils.h new file mode 100644 index 000000000000..993aa19de313 --- /dev/null +++ b/sbin/cgdconfig/argon2_utils.h @@ -0,0 +1,36 @@ +/* $NetBSD: argon2_utils.h,v 1.1 2021/11/22 14:34:35 nia Exp $ */ +/*- + * Copyright (c) 2021 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nia Alarie. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ARGON2_UTILS_H +#define ARGON2_UTILS_H +#include + +void argon2id_calibrate(size_t, size_t, size_t *, size_t *, size_t *); +#endif diff --git a/sbin/cgdconfig/cgdconfig.8 b/sbin/cgdconfig/cgdconfig.8 index 10e2b0fd8b3f..e7a274c26fbf 100644 --- a/sbin/cgdconfig/cgdconfig.8 +++ b/sbin/cgdconfig/cgdconfig.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: cgdconfig.8,v 1.50 2021/04/30 21:07:34 nia Exp $ +.\" $NetBSD: cgdconfig.8,v 1.51 2021/11/22 14:34:35 nia Exp $ .\" .\" Copyright (c) 2002, The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 18, 2021 +.Dd November 4, 2021 .Dt CGDCONFIG 8 .Os .Sh NAME @@ -164,6 +164,14 @@ evaluates all of the key generation methods in the parameters file and uses the exclusive-or of the outputs of all the methods. The methods and descriptions are as follows: .Bl -tag -width indentxxxxxxxxxxx +.It argon2id +This method requires a passphrase which is entered at configuration +time. +Argon2 is a memory-hard password hashing scheme and winner of the +2013-2015 Password Hashing Competition. +It has numerous parameters allowing its hardness to scale with the +performance of the system. +Recommended for passphrase-based initialization. .It pkcs5_pbkdf2/sha1 This method requires a passphrase which is entered at configuration time. @@ -231,8 +239,8 @@ scan for a valid FFS file system. .It re-enter prompt for passphrase twice, and ensure entered passphrases are identical. -This method only works with the pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2 key -generators. +This method only works with the argon2id, pkcs5_pbkdf2/sha1, and +pkcs5_pbkdf2 key generators. .El .Ss /etc/cgd/cgd.conf The file @@ -358,10 +366,22 @@ The command to execute. Only used for the shell_cmd key generation method. .It iterations Ar integer The number of iterations. -Only used for pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2. +Only used for argon2id, pkcs5_pbkdf2/sha1, and pkcs5_pbkdf2. .It salt Ar base64 The salt. -Only used for pkcs5_pbkdf2/sha1 and pkcs5_pbkdf2. +Only used for argon2id, pkcs5_pbkdf2/sha1, and pkcs5_pbkdf2. +.It memory Ar integer +Memory consumption in kilobytes. +Only used for argon2id. +.It parallelism Ar integer +Number of threads to use to compute the password hash. +Should be equivalent to the number of CPUs/hardware threads. +Only used for argon2id. +.It version Ar integer +Version of Argon2 to use. +Should be the most recent version, currently +.Dv 19 . +Only used for argon2id. .El .Sh FILES .Bl -tag -width indentxxxxxxxxxxxxxxxxxx -compact @@ -475,6 +495,15 @@ program's execution. .Xr fstab 5 , .Xr disklabel 8 , .Xr gpt 8 +.Rs +.%T "Argon2: the memory-hard function for password hashing and other applications" +.%A Alex Biryukov +.%A Daniel Dinu +.%A Dmitry Khovratovich +.%D 2017 +.%I University of Luxembourg +.%U https://www.password-hashing.net/ +.Re .Pp .Dq PKCS #5 v2.0: Password-Based Cryptography Standard , RSA Laboratories, March 25, 1999. @@ -483,5 +512,9 @@ The .Nm utility appeared in .Nx 2.0 . +.Pp +.Li argon2id +support appeared in +.Nx 10.0 . .Sh BUGS Pass phrases are limited to 1023 bytes. diff --git a/sbin/cgdconfig/cgdconfig.c b/sbin/cgdconfig/cgdconfig.c index 29dd5b663148..53bb2d414d04 100644 --- a/sbin/cgdconfig/cgdconfig.c +++ b/sbin/cgdconfig/cgdconfig.c @@ -1,4 +1,4 @@ -/* $NetBSD: cgdconfig.c,v 1.52 2021/06/16 23:22:08 riastradh Exp $ */ +/* $NetBSD: cgdconfig.c,v 1.53 2021/11/22 14:34:35 nia Exp $ */ /*- * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. @@ -33,9 +33,12 @@ #ifndef lint __COPYRIGHT("@(#) Copyright (c) 2002, 2003\ The NetBSD Foundation, Inc. All rights reserved."); -__RCSID("$NetBSD: cgdconfig.c,v 1.52 2021/06/16 23:22:08 riastradh Exp $"); +__RCSID("$NetBSD: cgdconfig.c,v 1.53 2021/11/22 14:34:35 nia Exp $"); #endif +#ifdef HAVE_ARGON2 +#include +#endif #include #include #include @@ -113,6 +116,9 @@ static void eliminate_cores(void); static bits_t *getkey(const char *, struct keygen *, size_t); static bits_t *getkey_storedkey(const char *, struct keygen *, size_t); static bits_t *getkey_randomkey(const char *, struct keygen *, size_t, int); +#ifdef HAVE_ARGON2 +static bits_t *getkey_argon2id(const char *, struct keygen *, size_t); +#endif static bits_t *getkey_pkcs5_pbkdf2(const char *, struct keygen *, size_t, int); static bits_t *getkey_shell_cmd(const char *, struct keygen *, size_t); @@ -337,6 +343,11 @@ getkey(const char *dev, struct keygen *kg, size_t len) case KEYGEN_URANDOMKEY: tmp = getkey_randomkey(dev, kg, len, 0); break; +#ifdef HAVE_ARGON2 + case KEYGEN_ARGON2ID: + tmp = getkey_argon2id(dev, kg, len); + break; +#endif case KEYGEN_PKCS5_PBKDF2_SHA1: tmp = getkey_pkcs5_pbkdf2(dev, kg, len, 0); break; @@ -454,6 +465,40 @@ getkey_pkcs5_pbkdf2(const char *target, struct keygen *kg, size_t keylen, return ret; } +#ifdef HAVE_ARGON2 +static bits_t * +getkey_argon2id(const char *target, struct keygen *kg, size_t keylen) +{ + bits_t *ret; + char *passp; + char buf[1024]; + uint8_t raw[256]; + int err; + + snprintf(buf, sizeof(buf), "%s's passphrase%s:", target, + pflag & PFLAG_GETPASS_ECHO ? " (echo)" : ""); + passp = maybe_getpass(buf); + if ((err = argon2_hash(kg->kg_iterations, kg->kg_memory, + kg->kg_parallelism, + passp, strlen(passp), + bits_getbuf(kg->kg_salt), + BITS2BYTES(bits_len(kg->kg_salt)), + raw, sizeof(raw), + NULL, 0, + Argon2_id, kg->kg_version)) != ARGON2_OK) { + warnx("failed to generate Argon2id key, error code %d", err); + return NULL; + } + + ret = bits_new(raw, keylen); + kg->kg_key = bits_dup(ret); + explicit_memset(passp, 0, strlen(passp)); + explicit_memset(raw, 0, sizeof(raw)); + free(passp); + return ret; +} +#endif + /*ARGSUSED*/ static bits_t * getkey_shell_cmd(const char *target, struct keygen *kg, size_t keylen) @@ -606,8 +651,9 @@ configure(int argc, char **argv, struct params *inparams, int flags) for (kg = p->keygen; (pflag & PFLAG_GETPASS_MASK) && kg; kg = kg->next) - if ((kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1) || - (kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD )) { + if (kg->kg_method == KEYGEN_ARGON2ID || + kg->kg_method == KEYGEN_PKCS5_PBKDF2_SHA1 || + kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD) { loop = 1; break; } @@ -984,22 +1030,39 @@ static int verify_reenter(struct params *p) { struct keygen *kg; - bits_t *orig_key, *key; + bits_t *orig_key, *key = NULL; int ret; ret = 0; for (kg = p->keygen; kg && !ret; kg = kg->next) { - if ((kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1) && - (kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD )) + if (kg->kg_method != KEYGEN_ARGON2ID && + kg->kg_method != KEYGEN_PKCS5_PBKDF2_SHA1 && + kg->kg_method != KEYGEN_PKCS5_PBKDF2_OLD) continue; orig_key = kg->kg_key; kg->kg_key = NULL; - /* add a compat flag till the _OLD method goes away */ - key = getkey_pkcs5_pbkdf2("re-enter device", kg, - bits_len(orig_key), - kg->kg_method == KEYGEN_PKCS5_PBKDF2_OLD); + switch (kg->kg_method) { +#ifdef HAVE_ARGON2 + case KEYGEN_ARGON2ID: + key = getkey_argon2id("re-enter device", kg, + bits_len(orig_key)); + break; +#endif + case KEYGEN_PKCS5_PBKDF2_SHA1: + key = getkey_pkcs5_pbkdf2("re-enter device", kg, + bits_len(orig_key), 0); + break; + case KEYGEN_PKCS5_PBKDF2_OLD: + key = getkey_pkcs5_pbkdf2("re-enter device", kg, + bits_len(orig_key), 1); + break; + default: + warnx("unsupported keygen method"); + kg->kg_key = orig_key; + return -1; + } ret = !bits_match(key, orig_key); diff --git a/sbin/cgdconfig/cgdlex.l b/sbin/cgdconfig/cgdlex.l index e5cea084b576..5a4aef9ae9eb 100644 --- a/sbin/cgdconfig/cgdlex.l +++ b/sbin/cgdconfig/cgdlex.l @@ -1,5 +1,5 @@ %{ -/* $NetBSD: cgdlex.l,v 1.5 2009/10/29 14:49:03 christos Exp $ */ +/* $NetBSD: cgdlex.l,v 1.6 2021/11/22 14:34:35 nia Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #include #ifndef lint -__RCSID("$NetBSD: cgdlex.l,v 1.5 2009/10/29 14:49:03 christos Exp $"); +__RCSID("$NetBSD: cgdlex.l,v 1.6 2021/11/22 14:34:35 nia Exp $"); #endif #include @@ -98,6 +98,9 @@ verify_method { RETTOKEN(VERIFY_METHOD); } keygen { RETTOKEN(KEYGEN); } salt { RETTOKEN(SALT); } iterations { RETTOKEN(ITERATIONS); } +memory { RETTOKEN(MEMORY); } +parallelism { RETTOKEN(PARALLELISM); } +version { RETTOKEN(VERSION); } key { RETTOKEN(KEY); } cmd { RETTOKEN(CMD); } keygen_method { RETTOKEN(KEYGEN_METHOD); } diff --git a/sbin/cgdconfig/cgdparse.y b/sbin/cgdconfig/cgdparse.y index 3090cdc7c206..5d3f70da871a 100644 --- a/sbin/cgdconfig/cgdparse.y +++ b/sbin/cgdconfig/cgdparse.y @@ -1,5 +1,5 @@ %{ -/* $NetBSD: cgdparse.y,v 1.5 2008/07/17 16:24:55 drochner Exp $ */ +/* $NetBSD: cgdparse.y,v 1.6 2021/11/22 14:34:35 nia Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #include #ifndef lint -__RCSID("$NetBSD: cgdparse.y,v 1.5 2008/07/17 16:24:55 drochner Exp $"); +__RCSID("$NetBSD: cgdparse.y,v 1.6 2021/11/22 14:34:35 nia Exp $"); #endif #include @@ -67,7 +67,7 @@ static struct params *yy_global_params; %token STRINGLIT %token ALGORITHM KEYLENGTH IVMETHOD VERIFY_METHOD -%token KEYGEN SALT ITERATIONS KEY CMD +%token KEYGEN SALT ITERATIONS MEMORY PARALLELISM VERSION KEY CMD %token EOL @@ -99,6 +99,9 @@ kgvars: /* empty */ { $$ = NULL; } kgvar: SALT bits EOL { $$ = keygen_salt($2); } | ITERATIONS INTEGER EOL { $$ = keygen_iterations($2); } + | MEMORY INTEGER EOL { $$ = keygen_memory($2); } + | PARALLELISM INTEGER EOL { $$ = keygen_parallelism($2); } + | VERSION INTEGER EOL { $$ = keygen_version($2); } | KEY bits EOL { $$ = keygen_key($2); } | CMD stringlit EOL { $$ = keygen_cmd($2); } | EOL { $$ = NULL; } diff --git a/sbin/cgdconfig/params.c b/sbin/cgdconfig/params.c index 1db6fef872b2..c45e0bffd251 100644 --- a/sbin/cgdconfig/params.c +++ b/sbin/cgdconfig/params.c @@ -1,4 +1,4 @@ -/* $NetBSD: params.c,v 1.31 2021/06/03 15:40:27 prlw1 Exp $ */ +/* $NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia Exp $ */ /*- * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include #ifndef lint -__RCSID("$NetBSD: params.c,v 1.31 2021/06/03 15:40:27 prlw1 Exp $"); +__RCSID("$NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia Exp $"); #endif #include @@ -45,6 +45,11 @@ __RCSID("$NetBSD: params.c,v 1.31 2021/06/03 15:40:27 prlw1 Exp $"); #include #include +#ifdef HAVE_ARGON2 +#include +#include "argon2_utils.h" +#endif + #include "params.h" #include "pkcs5_pbkdf2.h" #include "utils.h" @@ -314,6 +319,9 @@ keygen_new(void) kg = emalloc(sizeof(*kg)); kg->kg_method = KEYGEN_UNKNOWN; kg->kg_iterations = (size_t)-1; + kg->kg_memory = (size_t)-1; + kg->kg_parallelism = (size_t)-1; + kg->kg_version = (size_t)-1; kg->kg_salt = NULL; kg->kg_key = NULL; kg->kg_cmd = NULL; @@ -346,6 +354,34 @@ keygen_verify(const struct keygen *kg) if (!kg) return 1; switch (kg->kg_method) { +#ifdef HAVE_ARGON2 + case KEYGEN_ARGON2ID: + if (kg->kg_iterations == (size_t)-1) { + warnx("keygen argon2id must provide `iterations'"); + return 0; + } + if (kg->kg_memory == (size_t)-1) { + warnx("keygen argon2id must provide `memory'"); + return 0; + } + if (kg->kg_parallelism == (size_t)-1) { + warnx("keygen argon2id must provide `parallelism'"); + return 0; + } + if (kg->kg_version == (size_t)-1) { + warnx("keygen argon2id must provide `version'"); + return 0; + } + if (kg->kg_cmd) + warnx("keygen argon2id does not need a `cmd'"); + if (kg->kg_key) + warnx("keygen argon2id does not need a `key'"); + if (!kg->kg_salt) { + warnx("keygen argon2id must provide a salt"); + return 0; + } + break; +#endif case KEYGEN_PKCS5_PBKDF2_OLD: if (kg->kg_iterations == (size_t)-1) { warnx("keygen pkcs5_pbkdf2 must provide `iterations'"); @@ -445,6 +481,14 @@ keygen_filldefaults(struct keygen *kg, size_t keylen) case KEYGEN_URANDOMKEY: case KEYGEN_SHELL_CMD: break; +#ifdef HAVE_ARGON2 + case KEYGEN_ARGON2ID: + kg->kg_version = ARGON2_VERSION_NUMBER; + kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1); + argon2id_calibrate(BITS2BYTES(keylen), DEFAULT_SALTLEN, + &kg->kg_iterations, &kg->kg_memory, &kg->kg_parallelism); + break; +#endif case KEYGEN_PKCS5_PBKDF2_OLD: case KEYGEN_PKCS5_PBKDF2_SHA1: kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1); @@ -488,6 +532,15 @@ keygen_combine(struct keygen *kg1, struct keygen *kg2) if (kg2->kg_iterations != (size_t)-1 && kg2->kg_iterations > 0) kg1->kg_iterations = kg2->kg_iterations; + if (kg2->kg_memory != (size_t)-1 && kg2->kg_memory > 0) + kg1->kg_memory = kg2->kg_memory; + + if (kg2->kg_parallelism != (size_t)-1 && kg2->kg_parallelism > 0) + kg1->kg_parallelism = kg2->kg_parallelism; + + if (kg2->kg_version != (size_t)-1 && kg2->kg_version > 0) + kg1->kg_version = kg2->kg_version; + if (kg2->kg_salt) bits_assign(&kg1->kg_salt, kg2->kg_salt); @@ -506,6 +559,10 @@ keygen_method(string_t *in) struct keygen *kg = keygen_new(); const char *kgm = string_tocharstar(in); +#ifdef HAVE_ARGON2 + if (!strcmp("argon2id", kgm)) + kg->kg_method = KEYGEN_ARGON2ID; +#endif if (!strcmp("pkcs5_pbkdf2", kgm)) kg->kg_method = KEYGEN_PKCS5_PBKDF2_OLD; if (!strcmp("pkcs5_pbkdf2/sha1", kgm)) @@ -551,6 +608,33 @@ keygen_iterations(size_t in) return kg; } +struct keygen * +keygen_memory(size_t in) +{ + struct keygen *kg = keygen_new(); + + kg->kg_memory = in; + return kg; +} + +struct keygen * +keygen_parallelism(size_t in) +{ + struct keygen *kg = keygen_new(); + + kg->kg_parallelism = in; + return kg; +} + +struct keygen * +keygen_version(size_t in) +{ + struct keygen *kg = keygen_new(); + + kg->kg_version = in; + return kg; +} + void keygen_addlist(struct keygen **l, struct keygen *e) { @@ -743,6 +827,17 @@ keygen_fput(struct keygen *kg, int ts, FILE *f) case KEYGEN_URANDOMKEY: (void)fprintf(f, "urandomkey;\n"); break; +#ifdef HAVE_ARGON2 + case KEYGEN_ARGON2ID: + (void)fprintf(f, "argon2id {\n"); + print_kvpair_int(f, ts, "iterations", kg->kg_iterations); + print_kvpair_int(f, ts, "memory", kg->kg_memory); + print_kvpair_int(f, ts, "parallelism", kg->kg_parallelism); + print_kvpair_int(f, ts, "version", kg->kg_version); + print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt); + (void)fprintf(f, "};\n"); + break; +#endif case KEYGEN_PKCS5_PBKDF2_OLD: (void)fprintf(f, "pkcs5_pbkdf2 {\n"); print_kvpair_int(f, ts, "iterations", kg->kg_iterations); diff --git a/sbin/cgdconfig/params.h b/sbin/cgdconfig/params.h index aa865f40057a..754b2afb8155 100644 --- a/sbin/cgdconfig/params.h +++ b/sbin/cgdconfig/params.h @@ -1,4 +1,4 @@ -/* $NetBSD: params.h,v 1.11 2014/12/14 12:31:39 mlelstv Exp $ */ +/* $NetBSD: params.h,v 1.12 2021/11/22 14:34:35 nia Exp $ */ /*- * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. @@ -37,6 +37,9 @@ struct keygen { int kg_method; size_t kg_iterations; + size_t kg_memory; /* only used for Argon2 */ + size_t kg_parallelism; /* only used for Argon2 */ + size_t kg_version; /* only used for Argon2 */ bits_t *kg_salt; bits_t *kg_key; string_t *kg_cmd; @@ -63,6 +66,7 @@ struct params { #define KEYGEN_URANDOMKEY 0x4 #define KEYGEN_PKCS5_PBKDF2_SHA1 0x5 #define KEYGEN_SHELL_CMD 0x6 +#define KEYGEN_ARGON2ID 0x7 /* verification methods */ @@ -108,6 +112,9 @@ struct keygen *keygen_method(string_t *); struct keygen *keygen_set_method(struct keygen *, string_t *); struct keygen *keygen_salt(bits_t *); struct keygen *keygen_iterations(size_t); +struct keygen *keygen_memory(size_t); +struct keygen *keygen_parallelism(size_t); +struct keygen *keygen_version(size_t); struct keygen *keygen_key(bits_t *); struct keygen *keygen_cmd(string_t *);