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