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