1/* $NetBSD: params.c,v 1.35 2024/05/12 18:02:16 christos Exp $ */
2
3/*-
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland C. Dowdeswell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34__RCSID("$NetBSD: params.c,v 1.35 2024/05/12 18:02:16 christos Exp $");
35#endif
36
37#include <sys/types.h>
38#include <sys/param.h>
39
40#include <sys/sha2.h>
41#include <sys/stat.h>
42
43#include <err.h>
44#include <errno.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <util.h>
49#include <uuid.h>
50
51#ifdef HAVE_ARGON2
52#include <argon2.h>
53#include "argon2_utils.h"
54#endif
55
56#include "params.h"
57#include "pkcs5_pbkdf2.h"
58#include "utils.h"
59#include "cgdconfig.h"
60#include "extern.h"
61
62static void	params_init(struct params *);
63
64static void	print_kvpair_cstr(FILE *, int, const char *, const char *);
65static void	print_kvpair_string(FILE *, int, const char *, const string_t *);
66static void	print_kvpair_int(FILE *, int, const char *, size_t);
67static void	print_kvpair_b64(FILE *, int, int, const char *, bits_t *);
68
69static void	spaces(FILE *, int);
70
71/* keygen defaults */
72#define DEFAULT_SALTLEN		128
73#define DEFAULT_ITERATION_TIME	2000000		/* 1 second in microseconds */
74
75/* crypto defaults functions */
76static struct crypto_defaults {
77	char	alg[32];
78	int	keylen;
79} crypto_defaults[] = {
80	{ "adiantum",		256 },
81	{ "aes-cbc",		128 },
82	{ "aes-xts",		256 },
83	{ "3des-cbc",		192 },
84	{ "blowfish-cbc",	128 }
85};
86
87static int	crypt_defaults_lookup(const char *);
88
89struct params *
90params_new(void)
91{
92	struct params	*p;
93
94	p = emalloc(sizeof(*p));
95	params_init(p);
96	return p;
97}
98
99static void
100params_init(struct params *p)
101{
102
103	p->algorithm = NULL;
104	p->ivmeth = NULL;
105	p->key = NULL;
106	p->keylen = (size_t)-1;
107	p->bsize = (size_t)-1;
108	p->verify_method = VERIFY_UNKNOWN;
109	p->dep_keygen = NULL;
110	p->keygen = NULL;
111}
112
113void
114params_free(struct params *p)
115{
116
117	if (!p)
118		return;
119	string_free(p->algorithm);
120	string_free(p->ivmeth);
121	keygen_free(p->dep_keygen);
122	keygen_free(p->keygen);
123}
124
125struct params *
126params_combine(struct params *p1, struct params *p2)
127{
128	struct params *p;
129
130	if (p1)
131		p = p1;
132	else
133		p = params_new();
134
135	if (!p2)
136		return p;
137
138	if (p2->algorithm)
139		string_assign(&p->algorithm, p2->algorithm);
140	if (p2->ivmeth)
141		string_assign(&p->ivmeth, p2->ivmeth);
142	if (p2->keylen != (size_t)-1)
143		p->keylen = p2->keylen;
144	if (p2->bsize != (size_t)-1)
145		p->bsize = p2->bsize;
146	if (p2->verify_method != VERIFY_UNKNOWN)
147		p->verify_method = p2->verify_method;
148
149	p->dep_keygen = keygen_combine(p->dep_keygen, p2->dep_keygen);
150	keygen_addlist(&p->keygen, p2->keygen);
151
152	/*
153	 * at this point we should have moved all allocated data
154	 * in p2 into p, so we can free it.
155	 */
156	free(p2);
157	return p;
158}
159
160int
161params_filldefaults(struct params *p)
162{
163	size_t	i;
164
165	if (p->verify_method == VERIFY_UNKNOWN)
166		p->verify_method = VERIFY_NONE;
167	if (!p->ivmeth)
168		p->ivmeth = string_fromcharstar("encblkno1");
169	if (p->keylen == (size_t)-1) {
170		if (p->algorithm == NULL)
171			return -1;
172		i = crypt_defaults_lookup(string_tocharstar(p->algorithm));
173		if (i != (size_t)-1) {
174			p->keylen = crypto_defaults[i].keylen;
175		} else {
176			warnx("could not determine key length for unknown "
177			    "algorithm \"%s\"",
178			    string_tocharstar(p->algorithm));
179			return -1;
180		}
181	}
182	return 0;
183}
184
185/*
186 * params_verify traverses the parameters and all of the keygen methods
187 * looking for inconsistencies.  It outputs warnings on non-fatal errors
188 * such as unknown encryption methods, but returns failure on fatal
189 * conditions such as a PKCS5_PBKDF2 keygen without a salt.  It is intended
190 * to run before key generation.
191 */
192
193int
194params_verify(const struct params *p)
195{
196	static const char *encblkno[] = {
197	    "encblkno", "encblkno1", "encblkno8"
198	};
199	static size_t i;
200	const char *meth;
201
202	if (!p->algorithm) {
203		warnx("unspecified algorithm");
204		return 0;
205	}
206	/*
207	 * we only warn for the encryption method so that it is possible
208	 * to use an older cgdconfig(8) with a new kernel that supports
209	 * additional crypto algorithms.
210	 */
211	if (crypt_defaults_lookup(string_tocharstar(p->algorithm)) == -1)
212		warnx("unknown algorithm \"%s\"(warning)",
213		    string_tocharstar(p->algorithm));
214	/* same rationale with IV methods. */
215	if (!p->ivmeth) {
216		warnx("unspecified IV method");
217		return 0;
218	}
219
220	meth = string_tocharstar(p->ivmeth);
221	for (i = 0; i < __arraycount(encblkno); i++)
222		if (strcmp(encblkno[i], meth) == 0)
223			break;
224
225	if (i == __arraycount(encblkno))
226		warnx("unknown IV method \"%s\" (warning)", meth);
227
228	if (p->keylen == (size_t)-1) {
229		warnx("unspecified key length");
230		return 0;
231	}
232
233	return keygen_verify(p->keygen);
234}
235
236struct params *
237params_algorithm(string_t *in)
238{
239	struct params *p = params_new();
240
241	p->algorithm = in;
242	return p;
243}
244
245struct params *
246params_ivmeth(string_t *in)
247{
248	struct params *p = params_new();
249
250	p->ivmeth = in;
251	return p;
252}
253
254struct params *
255params_keylen(size_t in)
256{
257	struct params *p = params_new();
258
259	p->keylen = in;
260	return p;
261}
262
263struct params *
264params_bsize(size_t in)
265{
266	struct params *p = params_new();
267
268	p->bsize = in;
269	return p;
270}
271
272struct params *
273params_verify_method(string_t *in)
274{
275	struct params *p = params_new();
276	const char *vm = string_tocharstar(in);
277
278	if (!strcmp("none", vm))
279		p->verify_method = VERIFY_NONE;
280	if (!strcmp("disklabel", vm))
281		p->verify_method = VERIFY_DISKLABEL;
282	if (!strcmp("ffs", vm))
283		p->verify_method = VERIFY_FFS;
284	if (!strcmp("re-enter", vm))
285		p->verify_method = VERIFY_REENTER;
286	if (!strcmp("mbr", vm))
287		p->verify_method = VERIFY_MBR;
288	if (!strcmp("gpt", vm))
289		p->verify_method = VERIFY_GPT;
290#ifdef HAVE_ZFS
291	if (!strcmp("zfs", vm))
292		p->verify_method = VERIFY_ZFS;
293#endif
294
295	string_free(in);
296
297	if (p->verify_method == VERIFY_UNKNOWN)
298		warnx("params_setverify_method: unrecognized "
299		    "verify method \"%s\"", vm);
300	return p;
301}
302
303struct params *
304params_keygen(struct keygen *in)
305{
306	struct params *p = params_new();
307
308	p->keygen = in;
309	return p;
310}
311
312struct params *
313params_dep_keygen(struct keygen *in)
314{
315	struct params *p = params_new();
316
317	p->dep_keygen = in;
318	return p;
319}
320
321struct keygen *
322keygen_new(void)
323{
324	struct keygen *kg;
325
326	kg = emalloc(sizeof(*kg));
327	kg->kg_method = KEYGEN_UNKNOWN;
328	kg->kg_iterations = (size_t)-1;
329	kg->kg_memory = (size_t)-1;
330	kg->kg_parallelism = (size_t)-1;
331	kg->kg_version = (size_t)-1;
332	kg->kg_salt = NULL;
333	kg->kg_key = NULL;
334	kg->kg_cmd = NULL;
335	kg->kg_sharedid = NULL;
336	kg->kg_sharedalg = SHARED_ALG_UNKNOWN;
337	kg->kg_sharedlen = (size_t)-1;
338	kg->kg_sharedinfo = NULL;
339	kg->next = NULL;
340	return kg;
341}
342
343void
344keygen_free(struct keygen *kg)
345{
346
347	if (!kg)
348		return;
349	bits_free(kg->kg_salt);
350	bits_free(kg->kg_key);
351	string_free(kg->kg_cmd);
352	string_free(kg->kg_sharedid);
353	bits_free(kg->kg_sharedinfo);
354	keygen_free(kg->next);
355	free(kg);
356}
357
358/*
359 * keygen_verify traverses the keygen structures and ensures
360 * that the appropriate information is available.
361 */
362
363int
364keygen_verify(const struct keygen *kg)
365{
366
367	if (!kg)
368		return 1;
369	switch (kg->kg_method) {
370#ifdef HAVE_ARGON2
371	case KEYGEN_ARGON2ID:
372		if (kg->kg_iterations == (size_t)-1) {
373			warnx("keygen argon2id must provide `iterations'");
374			return 0;
375		}
376		if (kg->kg_memory == (size_t)-1) {
377			warnx("keygen argon2id must provide `memory'");
378			return 0;
379		}
380		if (kg->kg_parallelism == (size_t)-1) {
381			warnx("keygen argon2id must provide `parallelism'");
382			return 0;
383		}
384		if (kg->kg_version == (size_t)-1) {
385			warnx("keygen argon2id must provide `version'");
386			return 0;
387		}
388		if (kg->kg_cmd)
389			warnx("keygen argon2id does not need a `cmd'");
390		if (kg->kg_key)
391			warnx("keygen argon2id does not need a `key'");
392		if (!kg->kg_salt) {
393			warnx("keygen argon2id must provide a salt");
394			return 0;
395		}
396		break;
397#endif
398	case KEYGEN_PKCS5_PBKDF2_OLD:
399		if (kg->kg_iterations == (size_t)-1) {
400			warnx("keygen pkcs5_pbkdf2 must provide `iterations'");
401			return 0;
402		}
403		if (kg->kg_key)
404			warnx("keygen pkcs5_pbkdf2 does not need a `key'");
405		if (!kg->kg_salt) {
406			warnx("keygen pkcs5_pbkdf2 must provide a salt");
407			return 0;
408		}
409		if (kg->kg_cmd)
410			warnx("keygen pkcs5_pbkdf2 does not need a `cmd'");
411		break;
412	case KEYGEN_PKCS5_PBKDF2_SHA1:
413		if (kg->kg_iterations == (size_t)-1) {
414			warnx("keygen pkcs5_pbkdf2/sha1 must provide `iterations'");
415			return 0;
416		}
417		if (kg->kg_key)
418			warnx("keygen pkcs5_pbkdf2/sha1 does not need a `key'");
419		if (!kg->kg_salt) {
420			warnx("keygen pkcs5_pbkdf2/sha1 must provide a salt");
421			return 0;
422		}
423		if (kg->kg_cmd)
424			warnx("keygen pkcs5_pbkdf2/sha1 does not need a `cmd'");
425		break;
426	case KEYGEN_STOREDKEY:
427		if (kg->kg_iterations != (size_t)-1)
428			warnx("keygen storedkey does not need `iterations'");
429		if (!kg->kg_key) {
430			warnx("keygen storedkey must provide a key");
431			return 0;
432		}
433		if (kg->kg_salt)
434			warnx("keygen storedkey does not need `salt'");
435		if (kg->kg_cmd)
436			warnx("keygen storedkey does not need `cmd'");
437		break;
438	case KEYGEN_RANDOMKEY:
439	case KEYGEN_URANDOMKEY:
440		if (kg->kg_iterations != (size_t)-1)
441			warnx("keygen [u]randomkey does not need `iterations'");
442		if (kg->kg_key)
443			warnx("keygen [u]randomkey does not need `key'");
444		if (kg->kg_salt)
445			warnx("keygen [u]randomkey does not need `salt'");
446		if (kg->kg_cmd)
447			warnx("keygen [u]randomkey does not need `cmd'");
448		if (kg->kg_sharedid)
449			warnx("keygen [u]randomkey makes no sense shared");
450		break;
451	case KEYGEN_SHELL_CMD:
452		if (kg->kg_iterations != (size_t)-1)
453			warnx("keygen shell_cmd does not need `iterations'");
454		if (kg->kg_key)
455			warnx("keygen shell_cmd does not need `key'");
456		if (kg->kg_salt)
457			warnx("keygen shell_cmd does not need `salt'");
458		if (!kg->kg_cmd) {
459			warnx("keygen shell_cmd must provide a `cmd'");
460			return 0;
461		}
462		break;
463	}
464	return keygen_verify(kg->next);
465}
466
467struct keygen *
468keygen_generate(int method)
469{
470	struct keygen *kg;
471
472	kg = keygen_new();
473	if (!kg)
474		return NULL;
475
476	kg->kg_method = method;
477	return kg;
478}
479
480/*
481 * keygen_filldefaults walks the keygen list and fills in
482 * default values.  The defaults may be either calibrated
483 * or randomly generated so this function is designed to be
484 * called when generating a new parameters file, not when
485 * reading a parameters file.
486 */
487
488int
489keygen_filldefaults(struct keygen *kg, size_t keylen)
490{
491
492	if (!kg)
493		return 0;
494	switch (kg->kg_method) {
495	case KEYGEN_RANDOMKEY:
496	case KEYGEN_URANDOMKEY:
497	case KEYGEN_SHELL_CMD:
498		break;
499#ifdef HAVE_ARGON2
500	case KEYGEN_ARGON2ID:
501		kg->kg_version = ARGON2_VERSION_NUMBER;
502		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1);
503		argon2id_calibrate(BITS2BYTES(keylen), DEFAULT_SALTLEN,
504		    &kg->kg_iterations, &kg->kg_memory, &kg->kg_parallelism);
505		break;
506#endif
507	case KEYGEN_PKCS5_PBKDF2_OLD:
508	case KEYGEN_PKCS5_PBKDF2_SHA1:
509		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1);
510		kg->kg_iterations = pkcs5_pbkdf2_calibrate(BITS2BYTES(keylen),
511		    DEFAULT_ITERATION_TIME);
512		if (kg->kg_iterations < 1) {
513			warnx("could not calibrate pkcs5_pbkdf2");
514			return -1;
515		}
516		break;
517	case KEYGEN_STOREDKEY:
518		/* Generate a random stored key */
519		kg->kg_key = bits_getrandombits(keylen, 1);
520		if (!kg->kg_key) {
521			warnx("can't generate random bits for storedkey");
522			return -1;
523		}
524		break;
525	default:
526		return -1;
527	}
528
529	return keygen_filldefaults(kg->next, keylen);
530}
531
532/*
533 * Strip the storedkey entries in preparation for inserting a shared
534 * clause with a newly generated info string to derive this key from
535 * KDF.  The result is that the key generated here is independent of
536 * whatever storedkeys were involved in the old one, so there is no
537 * need to keep them around,
538 */
539void
540keygen_stripstored(struct keygen **kgp)
541{
542	struct keygen *kg, *to_free = NULL;
543
544	while ((kg = *kgp) != NULL) {
545		if (kg->kg_method == KEYGEN_STOREDKEY) {
546			*kgp = kg->next;
547			kg->next = to_free;
548			to_free = kg;
549		} else {
550			kgp = &kg->next;
551		}
552	}
553	keygen_free(to_free);
554}
555
556int
557keygen_makeshared(struct keygen *kg0)
558{
559	struct keygen *kg;
560
561	for (kg = kg0; kg != NULL; kg = kg->next) {
562		switch (kg->kg_method) {
563		case KEYGEN_RANDOMKEY:
564		case KEYGEN_URANDOMKEY:
565			warnx("(u)randomkey keygen cannot be shared");
566			return -1;
567		case KEYGEN_SHELL_CMD:
568#ifdef HAVE_ARGON2
569		case KEYGEN_ARGON2ID:
570#endif
571		case KEYGEN_PKCS5_PBKDF2_OLD:
572		case KEYGEN_PKCS5_PBKDF2_SHA1:
573			break;
574		case KEYGEN_STOREDKEY:
575			warnx("storedkey does not make sense as shared");
576			return -1;
577		default:
578			return -1;
579		}
580		if (kg->kg_sharedid != NULL) {
581			warnx("keygen already shared");
582			return -1;
583		}
584	}
585	for (kg = kg0; kg != NULL; kg = kg->next) {
586		struct uuid id;
587		char *idstr;
588		uint32_t status;
589
590		if (uuidgen(&id, 1) == -1) {
591			warn("uuidgen");
592			return -1;
593		}
594		uuid_to_string(&id, &idstr, &status);
595		if (status != uuid_s_ok) {
596			warnx("uuid_to_string: %"PRIu32, status);
597			return -1;
598		}
599
600		kg->kg_sharedid = string_fromcharstar(idstr);
601		kg->kg_sharedalg = SHARED_ALG_HKDF_HMAC_SHA256;
602		kg->kg_sharedlen = 8*SHA256_DIGEST_LENGTH;
603		kg->kg_sharedinfo = bits_getrandombits(DEFAULT_SALTLEN, 0);
604
605		free(idstr);
606	}
607	return 0;
608}
609
610int
611keygen_tweakshared(struct keygen *kg0)
612{
613	struct keygen *kg;
614
615	for (kg = kg0; kg != NULL; kg = kg->next) {
616		switch (kg->kg_method) {
617		case KEYGEN_RANDOMKEY:
618		case KEYGEN_URANDOMKEY:
619			warnx("(u)randomkey keygen cannot be shared");
620			return -1;
621		case KEYGEN_SHELL_CMD:
622#ifdef HAVE_ARGON2
623		case KEYGEN_ARGON2ID:
624#endif
625		case KEYGEN_PKCS5_PBKDF2_OLD:
626		case KEYGEN_PKCS5_PBKDF2_SHA1:
627			break;
628		case KEYGEN_STOREDKEY:
629			warnx("storedkey does not make sense as shared");
630			return -1;
631		default:
632			return -1;
633		}
634		if (kg->kg_sharedid == NULL) {
635			warnx("keygen not shared");
636			return -1;
637		}
638	}
639	for (kg = kg0; kg != NULL; kg = kg->next) {
640		if (kg->kg_method == KEYGEN_STOREDKEY)
641			continue;
642		bits_free(kg->kg_sharedinfo);
643		kg->kg_sharedinfo = bits_getrandombits(DEFAULT_SALTLEN, 0);
644	}
645	return 0;
646}
647
648struct keygen *
649keygen_combine(struct keygen *kg1, struct keygen *kg2)
650{
651	if (!kg1 && !kg2)
652		return NULL;
653
654	if (!kg1)
655		kg1 = keygen_new();
656
657	if (!kg2)
658		return kg1;
659
660	if (kg2->kg_method != KEYGEN_UNKNOWN)
661		kg1->kg_method = kg2->kg_method;
662
663	if (kg2->kg_iterations != (size_t)-1 && kg2->kg_iterations > 0)
664		kg1->kg_iterations = kg2->kg_iterations;
665
666	if (kg2->kg_memory != (size_t)-1 && kg2->kg_memory > 0)
667		kg1->kg_memory = kg2->kg_memory;
668
669	if (kg2->kg_parallelism != (size_t)-1 && kg2->kg_parallelism > 0)
670		kg1->kg_parallelism = kg2->kg_parallelism;
671
672	if (kg2->kg_version != (size_t)-1 && kg2->kg_version > 0)
673		kg1->kg_version = kg2->kg_version;
674
675	if (kg2->kg_salt)
676		bits_assign(&kg1->kg_salt, kg2->kg_salt);
677
678	if (kg2->kg_key)
679		bits_assign(&kg1->kg_key, kg2->kg_key);
680
681	if (kg2->kg_cmd)
682		string_assign(&kg1->kg_cmd, kg2->kg_cmd);
683
684	if (kg2->kg_sharedid)
685		string_assign(&kg1->kg_sharedid, kg2->kg_sharedid);
686	if (kg2->kg_sharedalg != SHARED_ALG_UNKNOWN) {
687		kg1->kg_sharedalg = kg2->kg_sharedalg;
688		kg1->kg_sharedlen = kg2->kg_sharedlen;
689	}
690	if (kg2->kg_sharedinfo)
691		bits_assign(&kg1->kg_sharedinfo, kg2->kg_sharedinfo);
692
693	return kg1;
694}
695
696struct keygen *
697keygen_method(string_t *in)
698{
699	struct keygen *kg = keygen_new();
700	const char *kgm = string_tocharstar(in);
701
702#ifdef HAVE_ARGON2
703	if (!strcmp("argon2id", kgm))
704		kg->kg_method = KEYGEN_ARGON2ID;
705#endif
706	if (!strcmp("pkcs5_pbkdf2", kgm))
707		kg->kg_method = KEYGEN_PKCS5_PBKDF2_OLD;
708	if (!strcmp("pkcs5_pbkdf2/sha1", kgm))
709		kg->kg_method = KEYGEN_PKCS5_PBKDF2_SHA1;
710	if (!strcmp("randomkey", kgm))
711		kg->kg_method = KEYGEN_RANDOMKEY;
712	if (!strcmp("storedkey", kgm))
713		kg->kg_method = KEYGEN_STOREDKEY;
714	if (!strcmp("urandomkey", kgm))
715		kg->kg_method = KEYGEN_URANDOMKEY;
716	if (!strcmp("shell_cmd", kgm))
717		kg->kg_method = KEYGEN_SHELL_CMD;
718
719	string_free(in);
720
721	if (kg->kg_method == KEYGEN_UNKNOWN)
722		warnx("unrecognized key generation method \"%s\"", kgm);
723	return kg;
724}
725
726struct keygen *
727keygen_set_method(struct keygen *kg, string_t *in)
728{
729
730	return keygen_combine(kg, keygen_method(in));
731}
732
733struct keygen *
734keygen_salt(bits_t *in)
735{
736	struct keygen *kg = keygen_new();
737
738	kg->kg_salt = in;
739	return kg;
740}
741
742struct keygen *
743keygen_iterations(size_t in)
744{
745	struct keygen *kg = keygen_new();
746
747	kg->kg_iterations = in;
748	return kg;
749}
750
751struct keygen *
752keygen_memory(size_t in)
753{
754	struct keygen *kg = keygen_new();
755
756	kg->kg_memory = in;
757	return kg;
758}
759
760struct keygen *
761keygen_parallelism(size_t in)
762{
763	struct keygen *kg = keygen_new();
764
765	kg->kg_parallelism = in;
766	return kg;
767}
768
769struct keygen *
770keygen_version(size_t in)
771{
772	struct keygen *kg = keygen_new();
773
774	kg->kg_version = in;
775	return kg;
776}
777
778void
779keygen_addlist(struct keygen **l, struct keygen *e)
780{
781	struct keygen *t;
782
783	if (*l) {
784		t = *l;
785		for (;t->next; t = t->next)
786			;
787		t->next = e;
788	} else {
789		*l = e;
790	}
791}
792
793struct keygen *
794keygen_key(bits_t *in)
795{
796	struct keygen *kg = keygen_new();
797
798	kg->kg_key = in;
799	return kg;
800}
801
802struct keygen *
803keygen_cmd(string_t *in)
804{
805	struct keygen *kg = keygen_new();
806
807	kg->kg_cmd = in;
808	return kg;
809}
810
811struct keygen *
812keygen_shared(string_t *id, string_t *alg, bits_t *info)
813{
814	struct keygen *kg = keygen_new();
815	const char *algname = string_tocharstar(alg);
816
817	if (!strcmp("hkdf-hmac-sha256", algname)) {
818		kg->kg_sharedalg = SHARED_ALG_HKDF_HMAC_SHA256;
819		kg->kg_sharedlen = 8*SHA256_DIGEST_LENGTH;
820	}
821
822	if (kg->kg_sharedalg == SHARED_ALG_UNKNOWN) {
823		warnx("unrecognized shared key derivation algorithm \"%s\"",
824		    algname);
825	}
826
827	kg->kg_sharedid = id;
828	kg->kg_sharedinfo = info;
829	return kg;
830}
831
832struct params *
833params_fget(FILE *f)
834{
835	struct params *p;
836
837	p = cgdparsefile(f);
838
839	if (!p)
840		return NULL;
841
842	/*
843	 * We deal with the deprecated keygen structure by prepending it
844	 * to the list of keygens, so that the rest of the code does not
845	 * have to deal with this backwards compat issue.  The deprecated
846	 * ``xor_key'' field may be stored in p->dep_keygen->kg_key.  If
847	 * it exists, we construct a storedkey keygen struct as well.  Also,
848	 * default the iteration count to 128 as the old code did.
849	 */
850
851	if (p->dep_keygen) {
852		if (p->dep_keygen->kg_iterations == (size_t)-1)
853			p->dep_keygen->kg_iterations = 128;
854		p->dep_keygen->next = p->keygen;
855		if (p->dep_keygen->kg_key) {
856			p->keygen = keygen_generate(KEYGEN_STOREDKEY);
857			p->keygen->kg_key = p->dep_keygen->kg_key;
858			p->dep_keygen->kg_key = NULL;
859			p->keygen->next = p->dep_keygen;
860		} else {
861			p->keygen = p->dep_keygen;
862		}
863		p->dep_keygen = NULL;
864	}
865	return p;
866}
867
868struct params *
869params_cget(const char *fn)
870{
871	struct params	*p;
872	FILE		*f;
873	char		filename[MAXPATHLEN];
874
875	if ((f = fopen(fn, "r")) == NULL && fn[0] != '/') {
876		snprintf(filename, sizeof(filename), "%s/%s",
877		    CGDCONFIG_DIR, fn);
878		fn = filename;
879		f = fopen(fn, "r");
880	}
881
882	if (f == NULL) {
883		warn("failed to open params file \"%s\"", fn);
884		return NULL;
885	}
886	p = params_fget(f);
887	(void)fclose(f);
888	return p;
889}
890
891#define WRAP_COL	50
892#define TAB_COL		8
893
894static void
895spaces(FILE *f, int len)
896{
897
898	while (len-- > 0)
899		(void)fputc(' ', f);
900}
901
902static void
903print_kvpair_cstr(FILE *f, int ts, const char *key, const char *val)
904{
905
906	spaces(f, ts);
907	(void)fprintf(f, "%s %s;\n", key, val);
908}
909
910static void
911print_kvpair_string(FILE *f, int ts, const char *key, const string_t *val)
912{
913
914	print_kvpair_cstr(f, ts, key, string_tocharstar(val));
915}
916
917static void
918print_kvpair_int(FILE *f, int ts, const char *key, size_t val)
919{
920	char	*tmp;
921
922	if (!key || val == (size_t)-1)
923		return;
924
925	if (asprintf(&tmp, "%zu", val) == -1)
926		err(1, NULL);
927	print_kvpair_cstr(f, ts, key, tmp);
928	free(tmp);
929}
930
931/*
932 * prints out a base64 encoded k-v pair to f.  It encodes the length
933 * of the bitstream as a 32bit unsigned integer in network byte order
934 * up front.
935 */
936
937static void
938print_kvpair_b64(FILE *f, int curpos, int ts, const char *key, bits_t *val)
939{
940	string_t	*str;
941	int		 i;
942	int		 len;
943	int		 pos;
944	const char	*out;
945
946	if (!key || !val)
947		return;
948
949	str = bits_encode(val);
950	out = string_tocharstar(str);
951	len = strlen(out);
952
953	spaces(f, ts);
954	(void)fprintf(f, "%s ", key);
955	curpos += ts + strlen(key) + 1;
956	ts = curpos;
957
958	for (i=0, pos=curpos; i < len; i++, pos++) {
959		if (pos > WRAP_COL) {
960			(void)fprintf(f, " \\\n");
961			spaces(f, ts);
962			pos = ts;
963		}
964		(void)fputc(out[i], f);
965	}
966	(void)fprintf(f, ";\n");
967	string_free(str);
968}
969
970static void
971print_shared(FILE *f, int ts, struct keygen *kg)
972{
973	static const char *const sharedalgs[] = {
974		[SHARED_ALG_UNKNOWN] = "unknown",
975		[SHARED_ALG_HKDF_HMAC_SHA256] = "hkdf-hmac-sha256",
976	};
977
978	if (kg->kg_sharedid == NULL ||
979	    kg->kg_sharedalg < 0 ||
980	    (size_t)kg->kg_sharedalg >= __arraycount(sharedalgs))
981		return;
982	fprintf(f, "%*sshared \"%s\" \\\n", ts, "",
983	    string_tocharstar(kg->kg_sharedid));
984	ts += 4;
985	fprintf(f, "%*salgorithm %s \\\n", ts, "",
986	    sharedalgs[kg->kg_sharedalg]);
987	print_kvpair_b64(f, 0, ts, "subkey", kg->kg_sharedinfo);
988}
989
990int
991keygen_fput(struct keygen *kg, int ts, FILE *f)
992{
993	int	curpos = 0;
994
995	if (!kg)
996		return 0;
997	(void)fprintf(f, "keygen ");
998	curpos += strlen("keygen ");
999	switch (kg->kg_method) {
1000	case KEYGEN_STOREDKEY:
1001		(void)fprintf(f, "storedkey ");
1002		curpos += strlen("storedkey ");
1003		print_kvpair_b64(f, curpos, 0, "key", kg->kg_key);
1004		break;
1005	case KEYGEN_RANDOMKEY:
1006		(void)fprintf(f, "randomkey;\n");
1007		break;
1008	case KEYGEN_URANDOMKEY:
1009		(void)fprintf(f, "urandomkey;\n");
1010		break;
1011#ifdef HAVE_ARGON2
1012	case KEYGEN_ARGON2ID:
1013		(void)fprintf(f, "argon2id {\n");
1014		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
1015		print_kvpair_int(f, ts, "memory", kg->kg_memory);
1016		print_kvpair_int(f, ts, "parallelism", kg->kg_parallelism);
1017		print_kvpair_int(f, ts, "version", kg->kg_version);
1018		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
1019		print_shared(f, ts, kg);
1020		(void)fprintf(f, "};\n");
1021		break;
1022#endif
1023	case KEYGEN_PKCS5_PBKDF2_OLD:
1024		(void)fprintf(f, "pkcs5_pbkdf2 {\n");
1025		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
1026		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
1027		print_shared(f, ts, kg);
1028		(void)fprintf(f, "};\n");
1029		break;
1030	case KEYGEN_PKCS5_PBKDF2_SHA1:
1031		(void)fprintf(f, "pkcs5_pbkdf2/sha1 {\n");
1032		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
1033		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
1034		print_shared(f, ts, kg);
1035		(void)fprintf(f, "};\n");
1036		break;
1037	default:
1038		warnx("keygen_fput: %d not a valid method", kg->kg_method);
1039		break;
1040	}
1041	return keygen_fput(kg->next, ts, f);
1042}
1043
1044int
1045params_fput(struct params *p, FILE *f)
1046{
1047	int	ts = 0;		/* tabstop of 0 spaces */
1048
1049	print_kvpair_string(f, ts, "algorithm", p->algorithm);
1050	print_kvpair_string(f, ts, "iv-method", p->ivmeth);
1051	print_kvpair_int(f, ts, "keylength", p->keylen);
1052	print_kvpair_int(f, ts, "blocksize", p->bsize);
1053	switch (p->verify_method) {
1054	case VERIFY_NONE:
1055		print_kvpair_cstr(f, ts, "verify_method", "none");
1056		break;
1057	case VERIFY_DISKLABEL:
1058		print_kvpair_cstr(f, ts, "verify_method", "disklabel");
1059		break;
1060	case VERIFY_FFS:
1061		print_kvpair_cstr(f, ts, "verify_method", "ffs");
1062		break;
1063	case VERIFY_REENTER:
1064		print_kvpair_cstr(f, ts, "verify_method", "re-enter");
1065		break;
1066	case VERIFY_MBR:
1067		print_kvpair_cstr(f, ts, "verify_method", "mbr");
1068		break;
1069	case VERIFY_GPT:
1070		print_kvpair_cstr(f, ts, "verify_method", "gpt");
1071		break;
1072#ifdef HAVE_ZFS
1073	case VERIFY_ZFS:
1074		print_kvpair_cstr(f, ts, "verify_method", "zfs");
1075		break;
1076#endif
1077	default:
1078		warnx("unsupported verify_method (%d)", p->verify_method);
1079		return -1;
1080	}
1081	return keygen_fput(p->keygen, TAB_COL, f);
1082}
1083
1084int
1085params_cput(struct params *p, const char *fn)
1086{
1087	FILE	*f;
1088
1089	if (fn && *fn) {
1090		if ((f = fopen(fn, "w")) == NULL) {
1091			warn("could not open outfile \"%s\"", fn);
1092			return -1;
1093		}
1094	} else {
1095		f = stdout;
1096	}
1097	return params_fput(p, f);
1098}
1099
1100static int
1101crypt_defaults_lookup(const char *alg)
1102{
1103	unsigned	i;
1104
1105	for (i=0; i < (sizeof(crypto_defaults) / sizeof(crypto_defaults[0])); i++)
1106		if (!strcmp(alg, crypto_defaults[i].alg))
1107			return i;
1108
1109	return -1;
1110}
1111