No empty .Rs/.Re
[netbsd-mini2440.git] / sbin / cgdconfig / params.c
blobd717ce7d32dab2e5da66054f521d0d4a039b5bb2
1 /* $NetBSD: params.c,v 1.23 2008/05/11 03:15:21 elric Exp $ */
3 /*-
4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland C. Dowdeswell.
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.
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.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: params.c,v 1.23 2008/05/11 03:15:21 elric Exp $");
35 #endif
37 #include <sys/types.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <util.h>
46 #include "params.h"
47 #include "pkcs5_pbkdf2.h"
48 #include "utils.h"
49 #include "extern.h"
51 static void params_init(struct params *);
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 *);
58 static void spaces(FILE *, int);
60 /* keygen defaults */
61 #define DEFAULT_SALTLEN 128
62 #define DEFAULT_ITERATION_TIME 2000000 /* 1 second in microseconds */
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 }
74 static int crypt_defaults_lookup(const char *);
76 struct params *
77 params_new(void)
79 struct params *p;
81 p = emalloc(sizeof(*p));
82 params_init(p);
83 return p;
86 static void
87 params_init(struct params *p)
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;
100 void
101 params_free(struct params *p)
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);
112 struct params *
113 params_combine(struct params *p1, struct params *p2)
115 struct params *p;
117 if (p1)
118 p = p1;
119 else
120 p = params_new();
122 if (!p2)
123 return p;
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;
136 p->dep_keygen = keygen_combine(p->dep_keygen, p2->dep_keygen);
137 keygen_addlist(&p->keygen, p2->keygen);
140 * at this point we should have moved all allocated data
141 * in p2 into p, so we can free it.
143 free(p2);
144 return p;
148 params_filldefaults(struct params *p)
150 size_t i;
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;
167 return 0;
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.
179 params_verify(const struct params *p)
181 static const char *encblkno[] = {
182 "encblkno", "encblkno1", "encblkno8"
184 static size_t i;
185 const char *meth;
187 if (!p->algorithm) {
188 warnx("unspecified algorithm");
189 return 0;
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.
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;
205 meth = string_tocharstar(p->ivmeth);
206 for (i = 0; i < __arraycount(encblkno); i++)
207 if (strcmp(encblkno[i], meth) == 0)
208 break;
210 if (i == __arraycount(encblkno))
211 warnx("unknown IV method \"%s\" (warning)", meth);
213 if (p->keylen == (size_t)-1) {
214 warnx("unspecified key length");
215 return 0;
218 return keygen_verify(p->keygen);
221 struct params *
222 params_algorithm(string_t *in)
224 struct params *p = params_new();
226 p->algorithm = in;
227 return p;
230 struct params *
231 params_ivmeth(string_t *in)
233 struct params *p = params_new();
235 p->ivmeth = in;
236 return p;
239 struct params *
240 params_keylen(size_t in)
242 struct params *p = params_new();
244 p->keylen = in;
245 return p;
248 struct params *
249 params_bsize(size_t in)
251 struct params *p = params_new();
253 p->bsize = in;
254 return p;
257 struct params *
258 params_verify_method(string_t *in)
260 struct params *p = params_new();
261 const char *vm = string_tocharstar(in);
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;
272 string_free(in);
274 if (p->verify_method == VERIFY_UNKNOWN)
275 warnx("params_setverify_method: unrecognized "
276 "verify method \"%s\"\n", vm);
277 return p;
280 struct params *
281 params_keygen(struct keygen *in)
283 struct params *p = params_new();
285 p->keygen = in;
286 return p;
289 struct params *
290 params_dep_keygen(struct keygen *in)
292 struct params *p = params_new();
294 p->dep_keygen = in;
295 return p;
298 struct keygen *
299 keygen_new(void)
301 struct keygen *kg;
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;
313 void
314 keygen_free(struct keygen *kg)
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);
327 * keygen_verify traverses the keygen structures and ensures
328 * that the appropriate information is available.
332 keygen_verify(const struct keygen *kg)
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;
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;
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;
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;
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;
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;
400 break;
402 return keygen_verify(kg->next);
405 struct keygen *
406 keygen_generate(int method)
408 struct keygen *kg;
410 kg = keygen_new();
411 if (!kg)
412 return NULL;
414 kg->kg_method = method;
415 return kg;
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.
427 keygen_filldefaults(struct keygen *kg, size_t keylen)
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;
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;
454 break;
455 default:
456 return -1;
459 return keygen_filldefaults(kg->next, keylen);
462 struct keygen *
463 keygen_combine(struct keygen *kg1, struct keygen *kg2)
465 if (!kg1 && !kg2)
466 return NULL;
468 if (!kg1)
469 kg1 = keygen_new();
471 if (!kg2)
472 return kg1;
474 if (kg2->kg_method != KEYGEN_UNKNOWN)
475 kg1->kg_method = kg2->kg_method;
477 if (kg2->kg_iterations != (size_t)-1 && kg2->kg_iterations > 0)
478 kg1->kg_iterations = kg2->kg_iterations;
480 if (kg2->kg_salt)
481 bits_assign(&kg1->kg_salt, kg2->kg_salt);
483 if (kg2->kg_key)
484 bits_assign(&kg1->kg_key, kg2->kg_key);
486 if (kg2->kg_cmd)
487 string_assign(&kg1->kg_cmd, kg2->kg_cmd);
489 return kg1;
492 struct keygen *
493 keygen_method(string_t *in)
495 struct keygen *kg = keygen_new();
496 const char *kgm = string_tocharstar(in);
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;
511 string_free(in);
513 if (kg->kg_method == KEYGEN_UNKNOWN)
514 warnx("unrecognized key generation method \"%s\"\n", kgm);
515 return kg;
518 struct keygen *
519 keygen_set_method(struct keygen *kg, string_t *in)
522 return keygen_combine(kg, keygen_method(in));
525 struct keygen *
526 keygen_salt(bits_t *in)
528 struct keygen *kg = keygen_new();
530 kg->kg_salt = in;
531 return kg;
534 struct keygen *
535 keygen_iterations(size_t in)
537 struct keygen *kg = keygen_new();
539 kg->kg_iterations = in;
540 return kg;
543 void
544 keygen_addlist(struct keygen **l, struct keygen *e)
546 struct keygen *t;
548 if (*l) {
549 t = *l;
550 for (;t->next; t = t->next)
552 t->next = e;
553 } else {
554 *l = e;
558 struct keygen *
559 keygen_key(bits_t *in)
561 struct keygen *kg = keygen_new();
563 kg->kg_key = in;
564 return kg;
567 struct keygen *
568 keygen_cmd(string_t *in)
570 struct keygen *kg = keygen_new();
572 kg->kg_cmd = in;
573 return kg;
576 struct params *
577 params_fget(FILE *f)
579 struct params *p;
581 p = cgdparsefile(f);
583 if (!p)
584 return NULL;
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.
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;
607 p->dep_keygen = NULL;
609 return p;
612 struct params *
613 params_cget(const char *fn)
615 struct params *p;
616 FILE *f;
618 if ((f = fopen(fn, "r")) == NULL) {
619 warn("failed to open params file \"%s\"", fn);
620 return NULL;
622 p = params_fget(f);
623 (void)fclose(f);
624 return p;
627 #define WRAP_COL 50
628 #define TAB_COL 8
630 static void
631 spaces(FILE *f, int len)
634 while (len-- > 0)
635 (void)fputc(' ', f);
638 static void
639 print_kvpair_cstr(FILE *f, int ts, const char *key, const char *val)
642 spaces(f, ts);
643 (void)fprintf(f, "%s %s;\n", key, val);
646 static void
647 print_kvpair_string(FILE *f, int ts, const char *key, const string_t *val)
650 print_kvpair_cstr(f, ts, key, string_tocharstar(val));
653 static void
654 print_kvpair_int(FILE *f, int ts, const char *key, size_t val)
656 char *tmp;
658 if (!key || val == (size_t)-1)
659 return;
661 if (asprintf(&tmp, "%zu", val) == -1)
662 err(1, NULL);
663 print_kvpair_cstr(f, ts, key, tmp);
664 free(tmp);
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.
673 static void
674 print_kvpair_b64(FILE *f, int curpos, int ts, const char *key, bits_t *val)
676 string_t *str;
677 int i;
678 int len;
679 int pos;
680 const char *out;
682 if (!key || !val)
683 return;
685 str = bits_encode(val);
686 out = string_tocharstar(str);
687 len = strlen(out);
689 spaces(f, ts);
690 (void)fprintf(f, "%s ", key);
691 curpos += ts + strlen(key) + 1;
692 ts = curpos;
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;
700 (void)fputc(out[i], f);
702 (void)fprintf(f, ";\n");
703 string_free(str);
707 keygen_fput(struct keygen *kg, int ts, FILE *f)
709 int curpos = 0;
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;
743 return keygen_fput(kg->next, ts, f);
747 params_fput(struct params *p, FILE *f)
749 int ts = 0; /* tabstop of 0 spaces */
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;
772 return keygen_fput(p->keygen, TAB_COL, f);
776 params_cput(struct params *p, const char *fn)
778 FILE *f;
780 if (fn && *fn) {
781 if ((f = fopen(fn, "w")) == NULL) {
782 warn("could not open outfile \"%s\"", fn);
783 return -1;
785 } else {
786 f = stdout;
788 return params_fput(p, f);
791 static int
792 crypt_defaults_lookup(const char *alg)
794 unsigned i;
796 for (i=0; i < (sizeof(crypto_defaults) / sizeof(crypto_defaults[0])); i++)
797 if (!strcmp(alg, crypto_defaults[i].alg))
798 return i;
800 return -1;