xref: /netbsd-src/sbin/cgdconfig/params.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /* $NetBSD: params.c,v 1.6 2003/04/10 05:45:29 elric 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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: params.c,v 1.6 2003/04/10 05:45:29 elric Exp $");
42 #endif
43 
44 #include <sys/types.h>
45 
46 #include <err.h>
47 #include <errno.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 
52 #include "params.h"
53 #include "pkcs5_pbkdf2.h"
54 #include "utils.h"
55 
56 /* from cgdparse.y */
57 struct params	*cgdparsefile(FILE *);
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 *, int);
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 milliseconds */
71 
72 /* crypto defaults functions */
73 struct crypto_defaults {
74 	char	alg[32];
75 	int	keylen;
76 } crypto_defaults[] = {
77 	{ "aes-cbc",		128 },
78 	{ "3des-cbc",		192 },
79 	{ "blowfish-cbc",	128 }
80 };
81 
82 static int	crypt_defaults_lookup(const char *);
83 
84 struct params *
85 params_new(void)
86 {
87 	struct params	*p;
88 
89 	p = malloc(sizeof(*p));
90 	params_init(p);
91 	return p;
92 }
93 
94 static void
95 params_init(struct params *p)
96 {
97 
98 	p->algorithm = NULL;
99 	p->ivmeth = NULL;
100 	p->key = NULL;
101 	p->keylen = -1;
102 	p->bsize = -1;
103 	p->verify_method = VERIFY_UNKNOWN;
104 	p->dep_keygen = NULL;
105 	p->keygen = NULL;
106 }
107 
108 void
109 params_free(struct params *p)
110 {
111 
112 	if (!p)
113 		return;
114 	string_free(p->algorithm);
115 	string_free(p->ivmeth);
116 	keygen_free(p->dep_keygen);
117 	keygen_free(p->keygen);
118 }
119 
120 struct params *
121 params_combine(struct params *p1, struct params *p2)
122 {
123 	struct params *p;
124 
125 	if (p1)
126 		p = p1;
127 	else
128 		p = params_new();
129 
130 	if (!p2)
131 		return p;
132 
133 	if (p2->algorithm)
134 		string_assign(&p->algorithm, p2->algorithm);
135 	if (p2->ivmeth)
136 		string_assign(&p->ivmeth, p2->ivmeth);
137 	if (p2->keylen != -1)
138 		p->keylen = p2->keylen;
139 	if (p2->bsize != -1)
140 		p->bsize = p2->bsize;
141 	if (p2->verify_method != VERIFY_UNKNOWN)
142 		p->verify_method = p2->verify_method;
143 
144 	p->dep_keygen = keygen_combine(p->dep_keygen, p2->dep_keygen);
145 	keygen_addlist(&p->keygen, p2->keygen);
146 
147 	/*
148 	 * at this point we should have moved all allocated data
149 	 * in p2 into p, so we can free it.
150 	 */
151 	free(p2);
152 	return p;
153 }
154 
155 int
156 params_filldefaults(struct params *p)
157 {
158 	int	i;
159 
160 	if (p->verify_method == VERIFY_UNKNOWN)
161 		p->verify_method = VERIFY_NONE;
162 	if (!p->ivmeth)
163 		p->ivmeth = string_fromcharstar("encblkno");
164 	if (p->keylen == -1) {
165 		i = crypt_defaults_lookup(string_tocharstar(p->algorithm));
166 		if (i != -1) {
167 			p->keylen = crypto_defaults[i].keylen;
168 		} else {
169 			warnx("could not determine key length for unknown "
170 			    "algorithm \"%s\"",
171 			    string_tocharstar(p->algorithm));
172 			return -1;
173 		}
174 	}
175 	return 0;
176 }
177 
178 /*
179  * params_verify traverses the parameters and all of the keygen methods
180  * looking for inconsistencies.  It outputs warnings on non-fatal errors
181  * such as unknown encryption methods, but returns failure on fatal
182  * conditions such as a PKCS5_PBKDF2 keygen without a salt.  It is intended
183  * to run before key generation.
184  */
185 
186 int
187 params_verify(const struct params *p)
188 {
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 	if (strcmp("encblkno", string_tocharstar(p->ivmeth)))
208 		warnx("unknown IV method \"%s\" (warning)",
209 		    string_tocharstar(p->ivmeth));
210 	if (p->keylen == -1) {
211 		warnx("unspecified key length");
212 		return 0;
213 	}
214 
215 	return keygen_verify(p->keygen);
216 }
217 
218 struct params *
219 params_algorithm(string_t *in)
220 {
221 	struct params *p = params_new();
222 
223 	p->algorithm = in;
224 	return p;
225 }
226 
227 struct params *
228 params_ivmeth(string_t *in)
229 {
230 	struct params *p = params_new();
231 
232 	p->ivmeth = in;
233 	return p;
234 }
235 
236 struct params *
237 params_keylen(int in)
238 {
239 	struct params *p = params_new();
240 
241 	p->keylen = in;
242 	return p;
243 }
244 
245 struct params *
246 params_bsize(int in)
247 {
248 	struct params *p = params_new();
249 
250 	p->bsize = in;
251 	return p;
252 }
253 
254 struct params *
255 params_verify_method(string_t *in)
256 {
257 	struct params *p = params_new();
258 	const char *vm = string_tocharstar(in);
259 
260 	if (!strcmp("none", vm))
261 		p->verify_method = VERIFY_NONE;
262 	if (!strcmp("disklabel", vm))
263 		p->verify_method = VERIFY_DISKLABEL;
264 	if (!strcmp("ffs", vm))
265 		p->verify_method = VERIFY_FFS;
266 
267 	string_free(in);
268 
269 	if (p->verify_method == VERIFY_UNKNOWN)
270 		fprintf(stderr, "params_setverify_method: unrecognized "
271 		    "verify method \"%s\"\n", vm);
272 	return p;
273 }
274 
275 struct params *
276 params_keygen(struct keygen *in)
277 {
278 	struct params *p = params_new();
279 
280 	p->keygen = in;
281 	return p;
282 }
283 
284 struct params *
285 params_dep_keygen(struct keygen *in)
286 {
287 	struct params *p = params_new();
288 
289 	p->dep_keygen = in;
290 	return p;
291 }
292 
293 struct keygen *
294 keygen_new(void)
295 {
296 	struct keygen *kg;
297 
298 	kg = malloc(sizeof(*kg));
299 	if (!kg)
300 		return NULL;
301 	kg->kg_method = KEYGEN_UNKNOWN;
302 	kg->kg_iterations = -1;
303 	kg->kg_salt = NULL;
304 	kg->kg_key = NULL;
305 	kg->next = NULL;
306 	return kg;
307 }
308 
309 void
310 keygen_free(struct keygen *kg)
311 {
312 
313 	if (!kg)
314 		return;
315 	bits_free(kg->kg_salt);
316 	bits_free(kg->kg_key);
317 	keygen_free(kg->next);
318 	free(kg);
319 }
320 
321 /*
322  * keygen_verify traverses the keygen structures and ensures
323  * that the appropriate information is available.
324  */
325 
326 int
327 keygen_verify(const struct keygen *kg)
328 {
329 
330 	if (!kg)
331 		return 1;
332 	switch (kg->kg_method) {
333 	case KEYGEN_PKCS5_PBKDF2:
334 		if (kg->kg_iterations == -1) {
335 			warnx("keygen pkcs5_pbkdf2 must provide `iterations'");
336 			return 0;
337 		}
338 		if (kg->kg_key)
339 			warnx("keygen pkcs5_pbkdf2 does not need a `key'");
340 		if (!kg->kg_salt) {
341 			warnx("keygen pkcs5_pbkdf2 must provide a salt");
342 			return 0;
343 		}
344 		break;
345 	case KEYGEN_STOREDKEY:
346 		if (kg->kg_iterations != -1)
347 			warnx("keygen storedkey does not need `iterations'");
348 		if (!kg->kg_key) {
349 			warnx("keygen storedkey must provide a key");
350 			return 0;
351 		}
352 		if (kg->kg_salt)
353 			warnx("keygen storedkey does not need `salt'");
354 		break;
355 	case KEYGEN_RANDOMKEY:
356 		if (kg->kg_iterations != -1)
357 			warnx("keygen randomkey does not need `iterations'");
358 		if (kg->kg_key)
359 			warnx("keygen randomkey does not need `key'");
360 		if (kg->kg_salt)
361 			warnx("keygen randomkey does not need `salt'");
362 		break;
363 	}
364 	return keygen_verify(kg->next);
365 }
366 
367 struct keygen *
368 keygen_generate(int method)
369 {
370 	struct keygen *kg;
371 
372 	kg = keygen_new();
373 	if (!kg)
374 		return NULL;
375 
376 	kg->kg_method = method;
377 	return kg;
378 }
379 
380 /*
381  * keygen_filldefaults walks the keygen list and fills in
382  * default values.  The defaults may be either calibrated
383  * or randomly generated so this function is designed to be
384  * called when generating a new parameters file, not when
385  * reading a parameters file.
386  */
387 
388 int
389 keygen_filldefaults(struct keygen *kg, int keylen)
390 {
391 
392 	if (!kg)
393 		return 0;
394 	switch (kg->kg_method) {
395 	case KEYGEN_RANDOMKEY:
396 		break;
397 	case KEYGEN_PKCS5_PBKDF2:
398 		kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN);
399 		kg->kg_iterations =
400 		    pkcs5_pbkdf2_calibrate(keylen, DEFAULT_ITERATION_TIME);
401 		if (kg->kg_iterations < 1) {
402 			fprintf(stderr, "%s: could not calibrate "
403 			    "pkcs5_pbkdf2\n", getprogname());
404 			return -1;
405 		}
406 		break;
407 	case KEYGEN_STOREDKEY:
408 		/* Generate a random stored key */
409 		kg->kg_key = bits_getrandombits(keylen);
410 		if (!kg->kg_key) {
411 			warnx("can't generate random bits for storedkey");
412 			return -1;
413 		}
414 		break;
415 	default:
416 		return -1;
417 	}
418 
419 	return keygen_filldefaults(kg->next, keylen);
420 }
421 
422 struct keygen *
423 keygen_combine(struct keygen *kg1, struct keygen *kg2)
424 {
425 	struct keygen *kg;
426 
427 	if (!kg1 && !kg2)
428 		return NULL;
429 
430 	if (kg1)
431 		kg = kg1;
432 	else
433 		kg = keygen_new();
434 
435 	if (!kg2)
436 		return kg;
437 
438 	if (kg2->kg_method != KEYGEN_UNKNOWN)
439 		kg->kg_method = kg2->kg_method;
440 	if (kg2->kg_iterations > 0)
441 		kg->kg_iterations = kg2->kg_iterations;
442 	if (kg2->kg_salt)
443 		bits_assign(&kg->kg_salt, kg2->kg_salt);
444 	if (kg2->kg_key)
445 		bits_assign(&kg->kg_key, kg2->kg_key);
446 	return kg;
447 }
448 
449 struct keygen *
450 keygen_method(string_t *in)
451 {
452 	struct keygen *kg = keygen_new();
453 	const char *kgm = string_tocharstar(in);
454 
455 	if (!strcmp("pkcs5_pbkdf2", kgm))
456 		kg->kg_method = KEYGEN_PKCS5_PBKDF2;
457 	if (!strcmp("randomkey", kgm))
458 		kg->kg_method = KEYGEN_RANDOMKEY;
459 	if (!strcmp("storedkey", kgm))
460 		kg->kg_method = KEYGEN_STOREDKEY;
461 
462 	string_free(in);
463 
464 	if (kg->kg_method == KEYGEN_UNKNOWN)
465 		fprintf(stderr, "unrecognized key generation method "
466 		    "\"%s\"\n", kgm);
467 	return kg;
468 }
469 
470 struct keygen *
471 keygen_set_method(struct keygen *kg, string_t *in)
472 {
473 
474 	return keygen_combine(kg, keygen_method(in));
475 }
476 
477 struct keygen *
478 keygen_salt(bits_t *in)
479 {
480 	struct keygen *kg = keygen_new();
481 
482 	kg->kg_salt = in;
483 	return kg;
484 }
485 
486 struct keygen *
487 keygen_iterations(int in)
488 {
489 	struct keygen *kg = keygen_new();
490 
491 	kg->kg_iterations = in;
492 	return kg;
493 }
494 
495 void
496 keygen_addlist(struct keygen **l, struct keygen *e)
497 {
498 	struct keygen *t;
499 
500 	if (*l) {
501 		t = *l;
502 		for (;t->next; t = t->next)
503 			;
504 		t->next = e;
505 	} else {
506 		*l = e;
507 	}
508 }
509 
510 struct keygen *
511 keygen_key(bits_t *in)
512 {
513 	struct keygen *kg = keygen_new();
514 
515 	kg->kg_key = in;
516 	return kg;
517 }
518 
519 struct params *
520 params_fget(FILE *f)
521 {
522 	struct params *p;
523 
524 	p = cgdparsefile(f);
525 
526 	if (!p)
527 		return NULL;
528 
529 	/*
530 	 * We deal with the deprecated keygen structure by prepending it
531 	 * to the list of keygens, so that the rest of the code does not
532 	 * have to deal with this backwards compat issue.  The deprecated
533 	 * ``xor_key'' field may be stored in p->dep_keygen->kg_key.  If
534 	 * it exists, we construct a storedkey keygen struct as well.  Also,
535 	 * default the iteration count to 128 as the old code did.
536 	 */
537 
538 	if (p->dep_keygen) {
539 		if (p->dep_keygen->kg_iterations == -1)
540 			p->dep_keygen->kg_iterations = 128;
541 		p->dep_keygen->next = p->keygen;
542 		if (p->dep_keygen->kg_key) {
543 			p->keygen = keygen_generate(KEYGEN_STOREDKEY);
544 			p->keygen->kg_key = p->dep_keygen->kg_key;
545 			p->dep_keygen->kg_key = NULL;
546 			p->keygen->next = p->dep_keygen;
547 		} else {
548 			p->keygen = p->dep_keygen;
549 		}
550 		p->dep_keygen = NULL;
551 	}
552 	return p;
553 }
554 
555 struct params *
556 params_cget(const char *fn)
557 {
558 	struct params	*p;
559 	FILE		*f;
560 
561 	f = fopen(fn, "r");
562 	if (!f) {
563 		fprintf(stderr, "failed to open params file \"%s\": %s\n",
564 		    fn, strerror(errno));
565 		return NULL;
566 	}
567 	p = params_fget(f);
568 	fclose(f);
569 	return p;
570 }
571 
572 #define WRAP_COL	50
573 #define TAB_COL		8
574 
575 static void
576 spaces(FILE *f, int len)
577 {
578 
579 	while (len-- > 0)
580 		fputc(' ', f);
581 }
582 
583 static void
584 print_kvpair_cstr(FILE *f, int ts, const char *key, const char *val)
585 {
586 
587 	spaces(f, ts);
588 	fprintf(f, "%s %s;\n", key, val);
589 }
590 
591 static void
592 print_kvpair_string(FILE *f, int ts, const char *key, const string_t *val)
593 {
594 
595 	print_kvpair_cstr(f, ts, key, string_tocharstar(val));
596 }
597 
598 static void
599 print_kvpair_int(FILE *f, int ts, const char *key, int val)
600 {
601 	char	*tmp;
602 
603 	if (!key || val == -1)
604 		return;
605 
606 	asprintf(&tmp, "%d", val);
607 	print_kvpair_cstr(f, ts, key, tmp);
608 	free(tmp);
609 }
610 
611 /*
612  * prints out a base64 encoded k-v pair to f.  It encodes the length
613  * of the bitstream as a 32bit unsigned integer in network byte order
614  * up front.
615  */
616 
617 static void
618 print_kvpair_b64(FILE *f, int curpos, int ts, const char *key, bits_t *val)
619 {
620 	string_t	*str;
621 	int		 i;
622 	int		 len;
623 	int		 pos;
624 	const char	*out;
625 
626 	if (!key || !val)
627 		return;
628 
629 	str = bits_encode(val);
630 	out = string_tocharstar(str);
631 	len = strlen(out);
632 
633 	spaces(f, ts);
634 	fprintf(f, "%s ", key);
635 	curpos += ts + strlen(key) + 1;
636 	ts = curpos;
637 
638 	for (i=0, pos=curpos; i < len; i++, pos++) {
639 		if (pos > WRAP_COL) {
640 			fprintf(f, " \\\n");
641 			spaces(f, ts);
642 			pos = ts;
643 		}
644 		fputc(out[i], f);
645 	}
646 	fprintf(f, ";\n");
647 	string_free(str);
648 }
649 
650 int
651 keygen_fput(struct keygen *kg, int ts, FILE *f)
652 {
653 	int	curpos = 0;
654 
655 	if (!kg)
656 		return 0;
657 	fprintf(f, "keygen ");
658 	curpos += strlen("keygen ");
659 	switch (kg->kg_method) {
660 	case KEYGEN_STOREDKEY:
661 		fprintf(f, "storedkey ");
662 		curpos += strlen("storedkey ");
663 		print_kvpair_b64(f, curpos, 0, "key", kg->kg_key);
664 		break;
665 	case KEYGEN_RANDOMKEY:
666 		fprintf(f, "randomkey;\n");
667 		break;
668 	case KEYGEN_PKCS5_PBKDF2:
669 		fprintf(f, "pkcs5_pbkdf2 {\n");
670 		print_kvpair_int(f, ts, "iterations", kg->kg_iterations);
671 		print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt);
672 		fprintf(f, "};\n");
673 		break;
674 	default:
675 		fprintf(stderr, "keygen_fput: %d not a valid method\n",
676 		    kg->kg_method);
677 		break;
678 	}
679 	return keygen_fput(kg->next, ts, f);
680 }
681 
682 int
683 params_fput(struct params *p, FILE *f)
684 {
685 	int	ts = 0;		/* tabstop of 0 spaces */
686 
687 	print_kvpair_string(f, ts, "algorithm", p->algorithm);
688 	print_kvpair_string(f, ts, "iv-method", p->ivmeth);
689 	print_kvpair_int(f, ts, "keylength", p->keylen);
690 	print_kvpair_int(f, ts, "blocksize", p->bsize);
691 	switch (p->verify_method) {
692 	case VERIFY_NONE:
693 		print_kvpair_cstr(f, ts, "verify_method", "none");
694 		break;
695 	case VERIFY_DISKLABEL:
696 		print_kvpair_cstr(f, ts, "verify_method", "disklabel");
697 		break;
698 	case VERIFY_FFS:
699 		print_kvpair_cstr(f, ts, "verify_method", "ffs");
700 		break;
701 	default:
702 		fprintf(stderr, "unsupported verify_method (%d)\n",
703 		    p->verify_method);
704 		return -1;
705 	}
706 	keygen_fput(p->keygen, TAB_COL, f);
707 	return 0;
708 }
709 
710 int
711 params_cput(struct params *p, const char *fn)
712 {
713 	FILE	*f;
714 
715 	if (fn && *fn) {
716 		f = fopen(fn, "w");
717 		if (!f) {
718 			fprintf(stderr, "could not open outfile \"%s\": %s\n",
719 			    fn, strerror(errno));
720 			perror("fopen");
721 			return -1;
722 		}
723 	} else {
724 		f = stdout;
725 	}
726 	return params_fput(p, f);
727 }
728 
729 static int
730 crypt_defaults_lookup(const char *alg)
731 {
732 	int	i;
733 
734 	for (i=0; i < sizeof(crypto_defaults); i++)
735 		if (!strcmp(alg, crypto_defaults[i].alg))
736 			break;
737 
738 	if (i >= sizeof(crypto_defaults))
739 		return -1;
740 	else
741 		return i;
742 }
743