xref: /netbsd-src/sbin/cgdconfig/params.c (revision f0fde9902fd4d72ded2807793acc7bfaa1ebf243)
1 /* $NetBSD: params.c,v 1.32 2021/11/22 14:34:35 nia 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.32 2021/11/22 14:34:35 nia Exp $");
35 #endif
36 
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 
41 #include <err.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <util.h>
47 
48 #ifdef HAVE_ARGON2
49 #include <argon2.h>
50 #include "argon2_utils.h"
51 #endif
52 
53 #include "params.h"
54 #include "pkcs5_pbkdf2.h"
55 #include "utils.h"
56 #include "cgdconfig.h"
57 #include "extern.h"
58 
59 static void	params_init(struct params *);
60 
61 static void	print_kvpair_cstr(FILE *, int, const char *, const char *);
62 static void	print_kvpair_string(FILE *, int, const char *, const string_t *);
63 static void	print_kvpair_int(FILE *, int, const char *, size_t);
64 static void	print_kvpair_b64(FILE *, int, int, const char *, bits_t *);
65 
66 static void	spaces(FILE *, int);
67 
68 /* keygen defaults */
69 #define DEFAULT_SALTLEN		128
70 #define DEFAULT_ITERATION_TIME	2000000		/* 1 second in microseconds */
71 
72 /* crypto defaults functions */
73 static struct crypto_defaults {
74 	char	alg[32];
75 	int	keylen;
76 } crypto_defaults[] = {
77 	{ "adiantum",		256 },
78 	{ "aes-cbc",		128 },
79 	{ "aes-xts",		256 },
80 	{ "3des-cbc",		192 },
81 	{ "blowfish-cbc",	128 }
82 };
83 
84 static int	crypt_defaults_lookup(const char *);
85 
86 struct params *
87 params_new(void)
88 {
89 	struct params	*p;
90 
91 	p = emalloc(sizeof(*p));
92 	params_init(p);
93 	return p;
94 }
95 
96 static void
97 params_init(struct params *p)
98 {
99 
100 	p->algorithm = NULL;
101 	p->ivmeth = NULL;
102 	p->key = NULL;
103 	p->keylen = (size_t)-1;
104 	p->bsize = (size_t)-1;
105 	p->verify_method = VERIFY_UNKNOWN;
106 	p->dep_keygen = NULL;
107 	p->keygen = NULL;
108 }
109 
110 void
111 params_free(struct params *p)
112 {
113 
114 	if (!p)
115 		return;
116 	string_free(p->algorithm);
117 	string_free(p->ivmeth);
118 	keygen_free(p->dep_keygen);
119 	keygen_free(p->keygen);
120 }
121 
122 struct params *
123 params_combine(struct params *p1, struct params *p2)
124 {
125 	struct params *p;
126 
127 	if (p1)
128 		p = p1;
129 	else
130 		p = params_new();
131 
132 	if (!p2)
133 		return p;
134 
135 	if (p2->algorithm)
136 		string_assign(&p->algorithm, p2->algorithm);
137 	if (p2->ivmeth)
138 		string_assign(&p->ivmeth, p2->ivmeth);
139 	if (p2->keylen != (size_t)-1)
140 		p->keylen = p2->keylen;
141 	if (p2->bsize != (size_t)-1)
142 		p->bsize = p2->bsize;
143 	if (p2->verify_method != VERIFY_UNKNOWN)
144 		p->verify_method = p2->verify_method;
145 
146 	p->dep_keygen = keygen_combine(p->dep_keygen, p2->dep_keygen);
147 	keygen_addlist(&p->keygen, p2->keygen);
148 
149 	/*
150 	 * at this point we should have moved all allocated data
151 	 * in p2 into p, so we can free it.
152 	 */
153 	free(p2);
154 	return p;
155 }
156 
157 int
158 params_filldefaults(struct params *p)
159 {
160 	size_t	i;
161 
162 	if (p->verify_method == VERIFY_UNKNOWN)
163 		p->verify_method = VERIFY_NONE;
164 	if (!p->ivmeth)
165 		p->ivmeth = string_fromcharstar("encblkno1");
166 	if (p->keylen == (size_t)-1) {
167 		if (p->algorithm == NULL)
168 			return -1;
169 		i = crypt_defaults_lookup(string_tocharstar(p->algorithm));
170 		if (i != (size_t)-1) {
171 			p->keylen = crypto_defaults[i].keylen;
172 		} else {
173 			warnx("could not determine key length for unknown "
174 			    "algorithm \"%s\"",
175 			    string_tocharstar(p->algorithm));
176 			return -1;
177 		}
178 	}
179 	return 0;
180 }
181 
182 /*
183  * params_verify traverses the parameters and all of the keygen methods
184  * looking for inconsistencies.  It outputs warnings on non-fatal errors
185  * such as unknown encryption methods, but returns failure on fatal
186  * conditions such as a PKCS5_PBKDF2 keygen without a salt.  It is intended
187  * to run before key generation.
188  */
189 
190 int
191 params_verify(const struct params *p)
192 {
193 	static const char *encblkno[] = {
194 	    "encblkno", "encblkno1", "encblkno8"
195 	};
196 	static size_t i;
197 	const char *meth;
198 
199 	if (!p->algorithm) {
200 		warnx("unspecified algorithm");
201 		return 0;
202 	}
203 	/*
204 	 * we only warn for the encryption method so that it is possible
205 	 * to use an older cgdconfig(8) with a new kernel that supports
206 	 * additional crypto algorithms.
207 	 */
208 	if (crypt_defaults_lookup(string_tocharstar(p->algorithm)) == -1)
209 		warnx("unknown algorithm \"%s\"(warning)",
210 		    string_tocharstar(p->algorithm));
211 	/* same rationale with IV methods. */
212 	if (!p->ivmeth) {
213 		warnx("unspecified IV method");
214 		return 0;
215 	}
216 
217 	meth = string_tocharstar(p->ivmeth);
218 	for (i = 0; i < __arraycount(encblkno); i++)
219 		if (strcmp(encblkno[i], meth) == 0)
220 			break;
221 
222 	if (i == __arraycount(encblkno))
223 		warnx("unknown IV method \"%s\" (warning)", meth);
224 
225 	if (p->keylen == (size_t)-1) {
226 		warnx("unspecified key length");
227 		return 0;
228 	}
229 
230 	return keygen_verify(p->keygen);
231 }
232 
233 struct params *
234 params_algorithm(string_t *in)
235 {
236 	struct params *p = params_new();
237 
238 	p->algorithm = in;
239 	return p;
240 }
241 
242 struct params *
243 params_ivmeth(string_t *in)
244 {
245 	struct params *p = params_new();
246 
247 	p->ivmeth = in;
248 	return p;
249 }
250 
251 struct params *
252 params_keylen(size_t in)
253 {
254 	struct params *p = params_new();
255 
256 	p->keylen = in;
257 	return p;
258 }
259 
260 struct params *
261 params_bsize(size_t in)
262 {
263 	struct params *p = params_new();
264 
265 	p->bsize = in;
266 	return p;
267 }
268 
269 struct params *
270 params_verify_method(string_t *in)
271 {
272 	struct params *p = params_new();
273 	const char *vm = string_tocharstar(in);
274 
275 	if (!strcmp("none", vm))
276 		p->verify_method = VERIFY_NONE;
277 	if (!strcmp("disklabel", vm))
278 		p->verify_method = VERIFY_DISKLABEL;
279 	if (!strcmp("ffs", vm))
280 		p->verify_method = VERIFY_FFS;
281 	if (!strcmp("re-enter", vm))
282 		p->verify_method = VERIFY_REENTER;
283 	if (!strcmp("mbr", vm))
284 		p->verify_method = VERIFY_MBR;
285 	if (!strcmp("gpt", vm))
286 		p->verify_method = VERIFY_GPT;
287 
288 	string_free(in);
289 
290 	if (p->verify_method == VERIFY_UNKNOWN)
291 		warnx("params_setverify_method: unrecognized "
292 		    "verify method \"%s\"", vm);
293 	return p;
294 }
295 
296 struct params *
297 params_keygen(struct keygen *in)
298 {
299 	struct params *p = params_new();
300 
301 	p->keygen = in;
302 	return p;
303 }
304 
305 struct params *
306 params_dep_keygen(struct keygen *in)
307 {
308 	struct params *p = params_new();
309 
310 	p->dep_keygen = in;
311 	return p;
312 }
313 
314 struct keygen *
315 keygen_new(void)
316 {
317 	struct keygen *kg;
318 
319 	kg = emalloc(sizeof(*kg));
320 	kg->kg_method = KEYGEN_UNKNOWN;
321 	kg->kg_iterations = (size_t)-1;
322 	kg->kg_memory = (size_t)-1;
323 	kg->kg_parallelism = (size_t)-1;
324 	kg->kg_version = (size_t)-1;
325 	kg->kg_salt = NULL;
326 	kg->kg_key = NULL;
327 	kg->kg_cmd = NULL;
328 	kg->next = NULL;
329 	return kg;
330 }
331 
332 void
333 keygen_free(struct keygen *kg)
334 {
335 
336 	if (!kg)
337 		return;
338 	bits_free(kg->kg_salt);
339 	bits_free(kg->kg_key);
340 	string_free(kg->kg_cmd);
341 	keygen_free(kg->next);
342 	free(kg);
343 }
344 
345 /*
346  * keygen_verify traverses the keygen structures and ensures
347  * that the appropriate information is available.
348  */
349 
350 int
351 keygen_verify(const struct keygen *kg)
352 {
353 
354 	if (!kg)
355 		return 1;
356 	switch (kg->kg_method) {
357 #ifdef HAVE_ARGON2
358 	case KEYGEN_ARGON2ID:
359 		if (kg->kg_iterations == (size_t)-1) {
360 			warnx("keygen argon2id must provide `iterations'");
361 			return 0;
362 		}
363 		if (kg->kg_memory == (size_t)-1) {
364 			warnx("keygen argon2id must provide `memory'");
365 			return 0;
366 		}
367 		if (kg->kg_parallelism == (size_t)-1) {
368 			warnx("keygen argon2id must provide `parallelism'");
369 			return 0;
370 		}
371 		if (kg->kg_version == (size_t)-1) {
372 			warnx("keygen argon2id must provide `version'");
373 			return 0;
374 		}
375 		if (kg->kg_cmd)
376 			warnx("keygen argon2id does not need a `cmd'");
377 		if (kg->kg_key)
378 			warnx("keygen argon2id does not need a `key'");
379 		if (!kg->kg_salt) {
380 			warnx("keygen argon2id must provide a salt");
381 			return 0;
382 		}
383 		break;
384 #endif
385 	case KEYGEN_PKCS5_PBKDF2_OLD:
386 		if (kg->kg_iterations == (size_t)-1) {
387 			warnx("keygen pkcs5_pbkdf2 must provide `iterations'");
388 			return 0;
389 		}
390 		if (kg->kg_key)
391 			warnx("keygen pkcs5_pbkdf2 does not need a `key'");
392 		if (!kg->kg_salt) {
393 			warnx("keygen pkcs5_pbkdf2 must provide a salt");
394 			return 0;
395 		}
396 		if (kg->kg_cmd)
397 			warnx("keygen pkcs5_pbkdf2 does not need a `cmd'");
398 		break;
399 	case KEYGEN_PKCS5_PBKDF2_SHA1:
400 		if (kg->kg_iterations == (size_t)-1) {
401 			warnx("keygen pkcs5_pbkdf2/sha1 must provide `iterations'");
402 			return 0;
403 		}
404 		if (kg->kg_key)
405 			warnx("keygen pkcs5_pbkdf2/sha1 does not need a `key'");
406 		if (!kg->kg_salt) {
407 			warnx("keygen pkcs5_pbkdf2/sha1 must provide a salt");
408 			return 0;
409 		}
410 		if (kg->kg_cmd)
411 			warnx("keygen pkcs5_pbkdf2/sha1 does not need a `cmd'");
412 		break;
413 	case KEYGEN_STOREDKEY:
414 		if (kg->kg_iterations != (size_t)-1)
415 			warnx("keygen storedkey does not need `iterations'");
416 		if (!kg->kg_key) {
417 			warnx("keygen storedkey must provide a key");
418 			return 0;
419 		}
420 		if (kg->kg_salt)
421 			warnx("keygen storedkey does not need `salt'");
422 		if (kg->kg_cmd)
423 			warnx("keygen storedkey does not need `cmd'");
424 		break;
425 	case KEYGEN_RANDOMKEY:
426 	case KEYGEN_URANDOMKEY:
427 		if (kg->kg_iterations != (size_t)-1)
428 			warnx("keygen [u]randomkey does not need `iterations'");
429 		if (kg->kg_key)
430 			warnx("keygen [u]randomkey does not need `key'");
431 		if (kg->kg_salt)
432 			warnx("keygen [u]randomkey does not need `salt'");
433 		if (kg->kg_cmd)
434 			warnx("keygen [u]randomkey does not need `cmd'");
435 		break;
436 	case KEYGEN_SHELL_CMD:
437 		if (kg->kg_iterations != (size_t)-1)
438 			warnx("keygen shell_cmd does not need `iterations'");
439 		if (kg->kg_key)
440 			warnx("keygen shell_cmd does not need `key'");
441 		if (kg->kg_salt)
442 			warnx("keygen shell_cmd does not need `salt'");
443 		if (!kg->kg_cmd) {
444 			warnx("keygen shell_cmd must provide a `cmd'");
445 			return 0;
446 		}
447 		break;
448 	}
449 	return keygen_verify(kg->next);
450 }
451 
452 struct keygen *
453 keygen_generate(int method)
454 {
455 	struct keygen *kg;
456 
457 	kg = keygen_new();
458 	if (!kg)
459 		return NULL;
460 
461 	kg->kg_method = method;
462 	return kg;
463 }
464 
465 /*
466  * keygen_filldefaults walks the keygen list and fills in
467  * default values.  The defaults may be either calibrated
468  * or randomly generated so this function is designed to be
469  * called when generating a new parameters file, not when
470  * reading a parameters file.
471  */
472 
473 int
474 keygen_filldefaults(struct keygen *kg, size_t keylen)
475 {
476 
477 	if (!kg)
478 		return 0;
479 	switch (kg->kg_method) {
480 	case KEYGEN_RANDOMKEY:
481 	case KEYGEN_URANDOMKEY:
482 	case KEYGEN_SHELL_CMD:
483 		break;
484 #ifdef HAVE_ARGON2
485 	case KEYGEN_ARGON2ID:
486 		kg->kg_version = ARGON2_VERSION_NUMBER;
487 		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1);
488 		argon2id_calibrate(BITS2BYTES(keylen), DEFAULT_SALTLEN,
489 		    &kg->kg_iterations, &kg->kg_memory, &kg->kg_parallelism);
490 		break;
491 #endif
492 	case KEYGEN_PKCS5_PBKDF2_OLD:
493 	case KEYGEN_PKCS5_PBKDF2_SHA1:
494 		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1);
495 		kg->kg_iterations = pkcs5_pbkdf2_calibrate(BITS2BYTES(keylen),
496 		    DEFAULT_ITERATION_TIME);
497 		if (kg->kg_iterations < 1) {
498 			warnx("could not calibrate pkcs5_pbkdf2");
499 			return -1;
500 		}
501 		break;
502 	case KEYGEN_STOREDKEY:
503 		/* Generate a random stored key */
504 		kg->kg_key = bits_getrandombits(keylen, 1);
505 		if (!kg->kg_key) {
506 			warnx("can't generate random bits for storedkey");
507 			return -1;
508 		}
509 		break;
510 	default:
511 		return -1;
512 	}
513 
514 	return keygen_filldefaults(kg->next, keylen);
515 }
516 
517 struct keygen *
518 keygen_combine(struct keygen *kg1, struct keygen *kg2)
519 {
520 	if (!kg1 && !kg2)
521 		return NULL;
522 
523 	if (!kg1)
524 		kg1 = keygen_new();
525 
526 	if (!kg2)
527 		return kg1;
528 
529 	if (kg2->kg_method != KEYGEN_UNKNOWN)
530 		kg1->kg_method = kg2->kg_method;
531 
532 	if (kg2->kg_iterations != (size_t)-1 && kg2->kg_iterations > 0)
533 		kg1->kg_iterations = kg2->kg_iterations;
534 
535 	if (kg2->kg_memory != (size_t)-1 && kg2->kg_memory > 0)
536 		kg1->kg_memory = kg2->kg_memory;
537 
538 	if (kg2->kg_parallelism != (size_t)-1 && kg2->kg_parallelism > 0)
539 		kg1->kg_parallelism = kg2->kg_parallelism;
540 
541 	if (kg2->kg_version != (size_t)-1 && kg2->kg_version > 0)
542 		kg1->kg_version = kg2->kg_version;
543 
544 	if (kg2->kg_salt)
545 		bits_assign(&kg1->kg_salt, kg2->kg_salt);
546 
547 	if (kg2->kg_key)
548 		bits_assign(&kg1->kg_key, kg2->kg_key);
549 
550 	if (kg2->kg_cmd)
551 		string_assign(&kg1->kg_cmd, kg2->kg_cmd);
552 
553 	return kg1;
554 }
555 
556 struct keygen *
557 keygen_method(string_t *in)
558 {
559 	struct keygen *kg = keygen_new();
560 	const char *kgm = string_tocharstar(in);
561 
562 #ifdef HAVE_ARGON2
563 	if (!strcmp("argon2id", kgm))
564 		kg->kg_method = KEYGEN_ARGON2ID;
565 #endif
566 	if (!strcmp("pkcs5_pbkdf2", kgm))
567 		kg->kg_method = KEYGEN_PKCS5_PBKDF2_OLD;
568 	if (!strcmp("pkcs5_pbkdf2/sha1", kgm))
569 		kg->kg_method = KEYGEN_PKCS5_PBKDF2_SHA1;
570 	if (!strcmp("randomkey", kgm))
571 		kg->kg_method = KEYGEN_RANDOMKEY;
572 	if (!strcmp("storedkey", kgm))
573 		kg->kg_method = KEYGEN_STOREDKEY;
574 	if (!strcmp("urandomkey", kgm))
575 		kg->kg_method = KEYGEN_URANDOMKEY;
576 	if (!strcmp("shell_cmd", kgm))
577 		kg->kg_method = KEYGEN_SHELL_CMD;
578 
579 	string_free(in);
580 
581 	if (kg->kg_method == KEYGEN_UNKNOWN)
582 		warnx("unrecognized key generation method \"%s\"", kgm);
583 	return kg;
584 }
585 
586 struct keygen *
587 keygen_set_method(struct keygen *kg, string_t *in)
588 {
589 
590 	return keygen_combine(kg, keygen_method(in));
591 }
592 
593 struct keygen *
594 keygen_salt(bits_t *in)
595 {
596 	struct keygen *kg = keygen_new();
597 
598 	kg->kg_salt = in;
599 	return kg;
600 }
601 
602 struct keygen *
603 keygen_iterations(size_t in)
604 {
605 	struct keygen *kg = keygen_new();
606 
607 	kg->kg_iterations = in;
608 	return kg;
609 }
610 
611 struct keygen *
612 keygen_memory(size_t in)
613 {
614 	struct keygen *kg = keygen_new();
615 
616 	kg->kg_memory = in;
617 	return kg;
618 }
619 
620 struct keygen *
621 keygen_parallelism(size_t in)
622 {
623 	struct keygen *kg = keygen_new();
624 
625 	kg->kg_parallelism = in;
626 	return kg;
627 }
628 
629 struct keygen *
630 keygen_version(size_t in)
631 {
632 	struct keygen *kg = keygen_new();
633 
634 	kg->kg_version = in;
635 	return kg;
636 }
637 
638 void
639 keygen_addlist(struct keygen **l, struct keygen *e)
640 {
641 	struct keygen *t;
642 
643 	if (*l) {
644 		t = *l;
645 		for (;t->next; t = t->next)
646 			;
647 		t->next = e;
648 	} else {
649 		*l = e;
650 	}
651 }
652 
653 struct keygen *
654 keygen_key(bits_t *in)
655 {
656 	struct keygen *kg = keygen_new();
657 
658 	kg->kg_key = in;
659 	return kg;
660 }
661 
662 struct keygen *
663 keygen_cmd(string_t *in)
664 {
665 	struct keygen *kg = keygen_new();
666 
667 	kg->kg_cmd = in;
668 	return kg;
669 }
670 
671 struct params *
672 params_fget(FILE *f)
673 {
674 	struct params *p;
675 
676 	p = cgdparsefile(f);
677 
678 	if (!p)
679 		return NULL;
680 
681 	/*
682 	 * We deal with the deprecated keygen structure by prepending it
683 	 * to the list of keygens, so that the rest of the code does not
684 	 * have to deal with this backwards compat issue.  The deprecated
685 	 * ``xor_key'' field may be stored in p->dep_keygen->kg_key.  If
686 	 * it exists, we construct a storedkey keygen struct as well.  Also,
687 	 * default the iteration count to 128 as the old code did.
688 	 */
689 
690 	if (p->dep_keygen) {
691 		if (p->dep_keygen->kg_iterations == (size_t)-1)
692 			p->dep_keygen->kg_iterations = 128;
693 		p->dep_keygen->next = p->keygen;
694 		if (p->dep_keygen->kg_key) {
695 			p->keygen = keygen_generate(KEYGEN_STOREDKEY);
696 			p->keygen->kg_key = p->dep_keygen->kg_key;
697 			p->dep_keygen->kg_key = NULL;
698 			p->keygen->next = p->dep_keygen;
699 		} else {
700 			p->keygen = p->dep_keygen;
701 		}
702 		p->dep_keygen = NULL;
703 	}
704 	return p;
705 }
706 
707 struct params *
708 params_cget(const char *fn)
709 {
710 	struct params	*p;
711 	FILE		*f;
712 	char		filename[MAXPATHLEN];
713 
714 	if ((f = fopen(fn, "r")) == NULL && fn[0] != '/') {
715 		snprintf(filename, sizeof(filename), "%s/%s",
716 		    CGDCONFIG_DIR, fn);
717 		fn = filename;
718 		f = fopen(fn, "r");
719 	}
720 
721 	if (f == NULL) {
722 		warn("failed to open params file \"%s\"", fn);
723 		return NULL;
724 	}
725 	p = params_fget(f);
726 	(void)fclose(f);
727 	return p;
728 }
729 
730 #define WRAP_COL	50
731 #define TAB_COL		8
732 
733 static void
734 spaces(FILE *f, int len)
735 {
736 
737 	while (len-- > 0)
738 		(void)fputc(' ', f);
739 }
740 
741 static void
742 print_kvpair_cstr(FILE *f, int ts, const char *key, const char *val)
743 {
744 
745 	spaces(f, ts);
746 	(void)fprintf(f, "%s %s;\n", key, val);
747 }
748 
749 static void
750 print_kvpair_string(FILE *f, int ts, const char *key, const string_t *val)
751 {
752 
753 	print_kvpair_cstr(f, ts, key, string_tocharstar(val));
754 }
755 
756 static void
757 print_kvpair_int(FILE *f, int ts, const char *key, size_t val)
758 {
759 	char	*tmp;
760 
761 	if (!key || val == (size_t)-1)
762 		return;
763 
764 	if (asprintf(&tmp, "%zu", val) == -1)
765 		err(1, NULL);
766 	print_kvpair_cstr(f, ts, key, tmp);
767 	free(tmp);
768 }
769 
770 /*
771  * prints out a base64 encoded k-v pair to f.  It encodes the length
772  * of the bitstream as a 32bit unsigned integer in network byte order
773  * up front.
774  */
775 
776 static void
777 print_kvpair_b64(FILE *f, int curpos, int ts, const char *key, bits_t *val)
778 {
779 	string_t	*str;
780 	int		 i;
781 	int		 len;
782 	int		 pos;
783 	const char	*out;
784 
785 	if (!key || !val)
786 		return;
787 
788 	str = bits_encode(val);
789 	out = string_tocharstar(str);
790 	len = strlen(out);
791 
792 	spaces(f, ts);
793 	(void)fprintf(f, "%s ", key);
794 	curpos += ts + strlen(key) + 1;
795 	ts = curpos;
796 
797 	for (i=0, pos=curpos; i < len; i++, pos++) {
798 		if (pos > WRAP_COL) {
799 			(void)fprintf(f, " \\\n");
800 			spaces(f, ts);
801 			pos = ts;
802 		}
803 		(void)fputc(out[i], f);
804 	}
805 	(void)fprintf(f, ";\n");
806 	string_free(str);
807 }
808 
809 int
810 keygen_fput(struct keygen *kg, int ts, FILE *f)
811 {
812 	int	curpos = 0;
813 
814 	if (!kg)
815 		return 0;
816 	(void)fprintf(f, "keygen ");
817 	curpos += strlen("keygen ");
818 	switch (kg->kg_method) {
819 	case KEYGEN_STOREDKEY:
820 		(void)fprintf(f, "storedkey ");
821 		curpos += strlen("storedkey ");
822 		print_kvpair_b64(f, curpos, 0, "key", kg->kg_key);
823 		break;
824 	case KEYGEN_RANDOMKEY:
825 		(void)fprintf(f, "randomkey;\n");
826 		break;
827 	case KEYGEN_URANDOMKEY:
828 		(void)fprintf(f, "urandomkey;\n");
829 		break;
830 #ifdef HAVE_ARGON2
831 	case KEYGEN_ARGON2ID:
832 		(void)fprintf(f, "argon2id {\n");
833 		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
834 		print_kvpair_int(f, ts, "memory", kg->kg_memory);
835 		print_kvpair_int(f, ts, "parallelism", kg->kg_parallelism);
836 		print_kvpair_int(f, ts, "version", kg->kg_version);
837 		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
838 		(void)fprintf(f, "};\n");
839 		break;
840 #endif
841 	case KEYGEN_PKCS5_PBKDF2_OLD:
842 		(void)fprintf(f, "pkcs5_pbkdf2 {\n");
843 		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
844 		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
845 		(void)fprintf(f, "};\n");
846 		break;
847 	case KEYGEN_PKCS5_PBKDF2_SHA1:
848 		(void)fprintf(f, "pkcs5_pbkdf2/sha1 {\n");
849 		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
850 		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
851 		(void)fprintf(f, "};\n");
852 		break;
853 	default:
854 		warnx("keygen_fput: %d not a valid method", kg->kg_method);
855 		break;
856 	}
857 	return keygen_fput(kg->next, ts, f);
858 }
859 
860 int
861 params_fput(struct params *p, FILE *f)
862 {
863 	int	ts = 0;		/* tabstop of 0 spaces */
864 
865 	print_kvpair_string(f, ts, "algorithm", p->algorithm);
866 	print_kvpair_string(f, ts, "iv-method", p->ivmeth);
867 	print_kvpair_int(f, ts, "keylength", p->keylen);
868 	print_kvpair_int(f, ts, "blocksize", p->bsize);
869 	switch (p->verify_method) {
870 	case VERIFY_NONE:
871 		print_kvpair_cstr(f, ts, "verify_method", "none");
872 		break;
873 	case VERIFY_DISKLABEL:
874 		print_kvpair_cstr(f, ts, "verify_method", "disklabel");
875 		break;
876 	case VERIFY_FFS:
877 		print_kvpair_cstr(f, ts, "verify_method", "ffs");
878 		break;
879 	case VERIFY_REENTER:
880 		print_kvpair_cstr(f, ts, "verify_method", "re-enter");
881 		break;
882 	case VERIFY_MBR:
883 		print_kvpair_cstr(f, ts, "verify_method", "mbr");
884 		break;
885 	case VERIFY_GPT:
886 		print_kvpair_cstr(f, ts, "verify_method", "gpt");
887 		break;
888 	default:
889 		warnx("unsupported verify_method (%d)", p->verify_method);
890 		return -1;
891 	}
892 	return keygen_fput(p->keygen, TAB_COL, f);
893 }
894 
895 int
896 params_cput(struct params *p, const char *fn)
897 {
898 	FILE	*f;
899 
900 	if (fn && *fn) {
901 		if ((f = fopen(fn, "w")) == NULL) {
902 			warn("could not open outfile \"%s\"", fn);
903 			return -1;
904 		}
905 	} else {
906 		f = stdout;
907 	}
908 	return params_fput(p, f);
909 }
910 
911 static int
912 crypt_defaults_lookup(const char *alg)
913 {
914 	unsigned	i;
915 
916 	for (i=0; i < (sizeof(crypto_defaults) / sizeof(crypto_defaults[0])); i++)
917 		if (!strcmp(alg, crypto_defaults[i].alg))
918 			return i;
919 
920 	return -1;
921 }
922