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