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