xref: /netbsd/sbin/cgdconfig/params.c (revision c4a72b64)
1 /* $NetBSD: params.c,v 1.4 2002/12/04 05:02:29 elric Exp $ */
2 
3 /*-
4  * Copyright (c) 2002 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");
42 #endif
43 
44 #include <sys/types.h>
45 
46 #include <errno.h>
47 #include <malloc.h>
48 #include <stdio.h>
49 #include <string.h>
50 
51 /* include the resolver gunk in order that we can use b64 routines */
52 #include <netinet/in.h>
53 #include <arpa/nameser.h>
54 #include <resolv.h>
55 
56 #include "params.h"
57 #include "utils.h"
58 
59 static int	params_setstring(char **, const char *);
60 static int	params_setbinary(u_int8_t **, int *, const char *, int);
61 static int	params_setb64(u_int8_t **, int *, const char *);
62 
63 static void	eatwhite(char *);
64 static int	take_action(struct params *, FILE *, const char *, char *);
65 static void	print_kvpair_str(FILE *, const char *, const char *);
66 static void	print_kvpair_int(FILE *, const char *, int);
67 static void	print_kvpair_b64(FILE *, const char *, const char *, int);
68 
69 static void	free_notnull(void *);
70 
71 /* crypt defaults functions */
72 #define CRYPT_DEFAULTKEYSIZE	0x01
73 
74 static int	crypt_int_lookup(char *, int);
75 static int	crypt_int_lookup_aes_cbc(int);
76 static int	crypt_int_lookup_3des_cbc(int);
77 static int	crypt_int_lookup_blowfish_cbc(int);
78 
79 void
80 params_init(struct params *p)
81 {
82 
83 	p->alg = NULL;
84 	p->ivmeth = NULL;
85 	p->key = NULL;
86 	p->keylen = -1;
87 	p->bsize = -1;
88 	p->keygen_method = KEYGEN_UNKNOWN;
89 	p->keygen_salt = NULL;
90 	p->keygen_saltlen = -1;
91 	p->keygen_iterations = -1;
92 	p->verify_method = VERIFY_UNKNOWN;
93 	p->key_hash = NULL;
94 	p->key_hashlen = -1;
95 	p->xor_key = NULL;
96 	p->xor_keylen = -1;
97 }
98 
99 void
100 params_free(struct params *p)
101 {
102 
103 	free_notnull(p->alg);
104 	free_notnull(p->ivmeth);
105 	free_notnull(p->keygen_salt);
106 	free_notnull(p->key_hash);
107 	free_notnull(p->xor_key);
108 }
109 
110 int
111 params_filldefaults(struct params *p)
112 {
113 
114 	if (p->keygen_method == KEYGEN_UNKNOWN)
115 		p->keygen_method = KEYGEN_PKCS5_PBKDF2;
116 	if (p->verify_method == VERIFY_UNKNOWN)
117 		p->verify_method = VERIFY_NONE;
118 	if (!p->ivmeth)
119 		params_setivmeth(p, "encblkno");
120 	if (p->keylen == -1)
121 		p->keylen = crypt_int_lookup(p->alg, CRYPT_DEFAULTKEYSIZE);
122 	if (p->keylen == -1) {
123 		fprintf(stderr, "Could not determine key length\n");
124 		return -1;
125 	}
126 	if (p->keygen_iterations < 1)
127 		p->keygen_iterations = 128;
128 	return 0;
129 }
130 
131 int
132 params_changed(const struct params *c)
133 {
134 
135 	if (c->alg || c->ivmeth || c->key || c->keylen != -1 ||
136 	    c->bsize != -1 || c->keygen_method || c->keygen_salt ||
137 	    c->keygen_saltlen != -1 || c->keygen_iterations != -1 ||
138 	    c->key_hash)
139 		return 1;
140 	return 0;
141 }
142 
143 static int
144 params_setstring(char **s, const char *in)
145 {
146 
147 	free_notnull(*s);
148 	*s = strdup(in);
149 	if (!in)
150 		return -1;
151 	return 0;
152 }
153 
154 /*
155  * params_setbinary allocates a buffer of at least len bits and
156  * fills it in.  It returns the number of bits in *l and the buffer
157  * in *s.
158  */
159 
160 static int
161 params_setbinary(u_int8_t **s, int *l, const char *in, int len)
162 {
163 
164 	*l = len;
165 	len = BITS2BYTES(len);
166 	*s = malloc(len);
167 	if (!*s)
168 		return -1;
169 	memcpy(*s, in, len);
170 	return 0;
171 }
172 
173 /*
174  * params_setb64 reads an encoded base64 stream.  We interpret
175  * the first 32 bits as an unsigned integer in network byte order
176  * specifying the number of bits in the stream.
177  */
178 
179 static int
180 params_setb64(u_int8_t **s, int *l, const char *in)
181 {
182 	int	 len;
183 	int	 nbits;
184 	char	*tmp;
185 
186 	len = strlen(in);
187 	tmp = malloc(len);
188 	if (!tmp)
189 		return -1;
190 
191 	len = __b64_pton(in, tmp, len);
192 
193 	if (len == -1) {
194 		fprintf(stderr, "params_setb64: mangled base64 stream\n");
195 		return -1;
196 	}
197 
198 	nbits = ntohl(*((u_int32_t *)tmp));
199 	if (nbits > (len - 4) * 8) {
200 		fprintf(stderr, "params_setb64: encoded bits claim to be "
201 		    "longer than they are (nbits=%u, stream len=%u bytes)\n",
202 		    (unsigned)nbits, (unsigned)len);
203 		return -1;
204 	}
205 
206 	*s = malloc(BITS2BYTES(nbits));
207 	if (!*s) {
208 		free(tmp);
209 		return -1;
210 	}
211 
212 	memcpy(*s, tmp + 4, BITS2BYTES(nbits));
213 
214 	*l = nbits;
215 	return *l;
216 }
217 
218 int
219 params_setalgorithm(struct params *p, const char *in)
220 {
221 
222 	return params_setstring(&p->alg, in);
223 }
224 
225 int
226 params_setivmeth(struct params *p, const char *in)
227 {
228 
229 	return params_setstring(&p->ivmeth, in);
230 }
231 
232 int
233 params_setkeylen(struct params *p, int keylen)
234 {
235 
236 	if (!keylen) {
237 		fprintf(stderr, "zero keylen not permitted\n");
238 		return -1;
239 	}
240 	p->keylen = keylen;
241 	return 0;
242 }
243 
244 int
245 params_setbsize(struct params *p, int bsize)
246 {
247 
248 	if (!bsize) {
249 		fprintf(stderr, "zero blocksize not permitted\n");
250 		return -1;
251 	}
252 	p->bsize = bsize;
253 	return 0;
254 }
255 
256 int
257 params_setkeygen_method(struct params *p, int in)
258 {
259 
260 	switch (in) {
261 	case KEYGEN_RANDOMKEY:
262 	case KEYGEN_PKCS5_PBKDF2:
263 		break;
264 	default:
265 		fprintf(stderr, "params_setkeygen_method: unsupported "
266 		    "keygen_method (%d)\n", in);
267 		return -1;
268 	}
269 
270 	p->keygen_method = in;
271 	return 0;
272 }
273 
274 int
275 params_setkeygen_method_str(struct params *p, const char *in)
276 {
277 
278 	if (!strcmp("pkcs5_pbkdf2", in))
279 		return params_setkeygen_method(p, KEYGEN_PKCS5_PBKDF2);
280 	if (!strcmp("randomkey", in))
281 		return params_setkeygen_method(p, KEYGEN_RANDOMKEY);
282 
283 	fprintf(stderr, "unrecognized key generation method \"%s\"\n", in);
284 	return -1;
285 }
286 
287 int
288 params_setkeygen_salt(struct params *p, const char *in, int len)
289 {
290 
291 	return params_setbinary(&p->keygen_salt, &p->keygen_saltlen, in, len);
292 }
293 
294 int
295 params_setkeygen_salt_b64(struct params *p, const char *in)
296 {
297 
298 	return params_setb64(&p->keygen_salt, &p->keygen_saltlen, in);
299 }
300 
301 int
302 params_setkeygen_iterations(struct params *p, int in)
303 {
304 
305 	if (in < 1) {
306 		fprintf(stderr, "keygen_iterations < 1 not permitted\n");
307 		return -1;
308 	}
309 	p->keygen_iterations = in;
310 	return 0;
311 }
312 
313 int
314 params_setverify_method(struct params *p, int in)
315 {
316 
317 	switch (in) {
318 	case VERIFY_NONE:
319 	case VERIFY_DISKLABEL:
320 		break;
321 	default:
322 		fprintf(stderr, "params_setverify_method: unsupported "
323 		    "verify_method (%d)\n", in);
324 		return -1;
325 	}
326 	p->verify_method = in;
327 	return 0;
328 }
329 
330 int
331 params_setverify_method_str(struct params *p, const char *in)
332 {
333 
334 	if (!strcmp("none", in))
335 		return params_setverify_method(p, VERIFY_NONE);
336 	if (!strcmp("disklabel", in))
337 		return params_setverify_method(p, VERIFY_DISKLABEL);
338 
339 	fprintf(stderr, "params_setverify_method: unrecognized verify method "
340 	    "\"%s\"\n", in);
341 	return -1;
342 }
343 
344 int
345 params_setxor_key(struct params *p, const char *in, int len)
346 {
347 
348 	return params_setbinary(&p->xor_key, &p->xor_keylen, in, len);
349 }
350 
351 int
352 params_setxor_key_b64(struct params *p, const char *in)
353 {
354 
355 	return params_setb64(&p->xor_key, &p->xor_keylen, in);
356 }
357 
358 int
359 params_setkey_hash(struct params *p, const char *in, int len)
360 {
361 
362 	return params_setbinary(&p->key_hash, &p->key_hashlen, in, len);
363 }
364 
365 int
366 params_setkey_hash_b64(struct params *p, const char *in)
367 {
368 
369 	return params_setb64(&p->key_hash, &p->key_hashlen, in);
370 }
371 
372 /* eatwhite simply removes all the whitespace from a string, in line */
373 static void
374 eatwhite(char *s)
375 {
376 	int	i, j;
377 
378 	for (i=0,j=0; s[i]; i++)
379 		if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n')
380 			s[j++] = s[i];
381 	s[j++] = '\0';
382 }
383 
384 static int
385 take_action(struct params *c, FILE *f, const char *key, char *val)
386 {
387 	int	ret;
388 
389 	eatwhite(val);
390 
391 	if (!strcmp(key, "algorithm")) {
392 		return params_setalgorithm(c, val);
393 	} else if (!strcmp(key, "iv-method")) {
394 		return params_setivmeth(c, val);
395 	} else if (!strcmp(key, "keylength")) {
396 		return params_setkeylen(c, atoi(val));
397 	} else if (!strcmp(key, "blocksize")) {
398 		return params_setbsize(c, atoi(val));
399 	} else if (!strcmp(key, "keygen_method")) {
400 		return params_setkeygen_method_str(c, val);
401 	} else if (!strcmp(key, "keygen_salt")) {
402 		ret = params_setkeygen_salt_b64(c, val);
403 		if (ret < 0) {
404 			fprintf(stderr, "keygen_salt improperly encoded\n");
405 			return -1;
406 		}
407 	} else if (!strcmp(key, "keygen_iterations")) {
408 		return params_setkeygen_iterations(c, atoi(val));
409 	} else if (!strcmp(key, "xor_key")) {
410 		ret = params_setxor_key_b64(c, val);
411 		if (ret < 0) {
412 			fprintf(stderr, "xor_key improperly encoded\n");
413 			return -1;
414 		}
415 	} else if (!strcmp(key, "verify_method")) {
416 		return params_setverify_method_str(c, val);
417 	} else if (!strcmp(key, "key_hash")) {
418 		ret = params_setkey_hash_b64(c, val);
419 		if (ret < 0) {
420 			fprintf(stderr, "key_hash improperly encoded\n");
421 			return -1;
422 		}
423 	} else {
424 		fprintf(stderr, "unrecognised keyword (%s, %s)\n", key, val);
425 		return -1;
426 	}
427 	return 0;
428 }
429 
430 int
431 params_fget(struct params *p, FILE *f)
432 {
433 	size_t	 len;
434 	size_t	 lineno;
435 	int	 ret;
436 	char	*line;
437 	char	*val;
438 
439 	lineno = 0;
440 	for (;;) {
441 		line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL);
442 		if (!line)
443 			break;
444 		if (!*line)
445 			continue;
446 
447 		/*
448 		 * our parameters file has two tokens per line,
449 		 * so we cut it up that way and ignore other cases.
450 		 */
451 		val = strpbrk(line, " \t");
452 		if (!val) {
453 			fprintf(stderr, "syntax error on line %lu\n",
454 			    (u_long)lineno);
455 			return -1;
456 		}
457 		*val++ = '\0';
458 
459 		ret = take_action(p, f, line, val);
460 		if (ret) {
461 			fprintf(stderr, "parse failure on line %lu\n",
462 			    (u_long)lineno);
463 			return -1;
464 		}
465 	}
466 	return 0;
467 }
468 
469 int
470 params_cget(struct params *p, const char *fn)
471 {
472 	FILE	*f;
473 
474 	f = fopen(fn, "r");
475 	if (!f) {
476 		fprintf(stderr, "failed to open params file \"%s\": %s\n",
477 		    fn, strerror(errno));
478 		return -1;
479 	}
480 	return params_fget(p, f);
481 }
482 
483 static void
484 print_kvpair_str(FILE *f, const char *key, const char *val)
485 {
486 
487 	if (key && val)
488 		fprintf(f, "%-25.25s%s\n", key, val);
489 }
490 
491 static void
492 print_kvpair_int(FILE *f, const char *key, int val)
493 {
494 
495 	if (key && val != -1)
496 		fprintf(f, "%-25.25s%d\n", key, val);
497 }
498 
499 /*
500  * prints out a base64 encoded k-v pair to f.  It encodes the length
501  * of the bitstream as a 32bit unsigned integer in network byte order
502  * up front.
503  */
504 
505 static void
506 print_kvpair_b64(FILE *f, const char *key, const char *val, int vallen)
507 {
508 	int	 col;
509 	int	 i;
510 	int	 len;
511 	char	*out;
512 	char	*tmp;
513 
514 	if (!key || !val || vallen == -1)
515 		return;
516 
517 	/* compute the total size of the input stream */
518 	len = BITS2BYTES(vallen) + 4;
519 
520 	tmp = malloc(len);
521 	out = malloc(len * 2);
522 	/* XXXrcd: errors ? */
523 	if (!tmp || !out)
524 		abort();	/* lame error handling here... */
525 
526 	/* stuff the length up front */
527 	*((u_int32_t *)tmp) = htonl(vallen);
528 	memcpy(tmp + 4, val, len - 4);
529 
530 	len = __b64_ntop(tmp, len, out, len * 2);
531 	free(tmp);
532 
533 	fprintf(f, "%-25.25s", key);
534 	col = 0;
535 	for (i=0; i < len; i++) {
536 		fputc(out[i], f);
537 		if (col++ > 40) {
538 			fprintf(f, " \\\n%-25.25s", "");
539 			col = 0;
540 		}
541 	}
542 	fprintf(f, "\n");
543 	free(out);
544 }
545 
546 int
547 params_fput(struct params *p, FILE *f)
548 {
549 
550 	print_kvpair_str(f, "algorithm", p->alg);
551 	print_kvpair_str(f, "iv-method", p->ivmeth);
552 	print_kvpair_int(f, "keylength", p->keylen);
553 	print_kvpair_int(f, "blocksize", p->bsize);
554 	switch (p->verify_method) {
555 	case VERIFY_NONE:
556 		print_kvpair_str(f, "verify_method", "none");
557 		break;
558 	case VERIFY_DISKLABEL:
559 		print_kvpair_str(f, "verify_method", "disklabel");
560 		break;
561 	default:
562 		fprintf(stderr, "unsupported verify_method (%d)\n",
563 		    p->verify_method);
564 		return -1;
565 	}
566 	switch (p->keygen_method) {
567 	case KEYGEN_RANDOMKEY:
568 		print_kvpair_str(f, "keygen_method", "randomkey");
569 		break;
570 	case KEYGEN_PKCS5_PBKDF2:
571 		print_kvpair_str(f, "keygen_method", "pkcs5_pbkdf2");
572 		print_kvpair_b64(f, "keygen_salt", p->keygen_salt,
573 		    p->keygen_saltlen);
574 		print_kvpair_int(f, "keygen_iterations", p->keygen_iterations);
575 		print_kvpair_b64(f, "xor_key", p->xor_key, p->xor_keylen);
576 		print_kvpair_b64(f, "key_hash", p->key_hash, p->key_hashlen);
577 		break;
578 	default:
579 		fprintf(stderr, "unsupported keygen_method (%d)\n",
580 		    p->keygen_method);
581 		return -1;
582 	}
583 	return 0;
584 }
585 
586 static int
587 crypt_int_lookup(char *alg, int type)
588 {
589 
590 	if (!strcmp(alg, "aes-cbc"))
591 		return crypt_int_lookup_aes_cbc(type);
592 	if (!strcmp(alg, "3des-cbc"))
593 		return crypt_int_lookup_3des_cbc(type);
594 	if (!strcmp(alg, "blowfish-cbc"))
595 		return crypt_int_lookup_blowfish_cbc(type);
596 
597 	return -1;
598 }
599 
600 static int
601 crypt_int_lookup_aes_cbc(int type)
602 {
603 
604 	switch (type) {
605 	case CRYPT_DEFAULTKEYSIZE:
606 		return 256;
607 	}
608 
609 	return -1;
610 }
611 
612 static int
613 crypt_int_lookup_3des_cbc(int type)
614 {
615 
616 	switch (type) {
617 	case CRYPT_DEFAULTKEYSIZE:
618 		return 192;
619 	}
620 
621 	return -1;
622 }
623 
624 static int
625 crypt_int_lookup_blowfish_cbc(int type)
626 {
627 
628 	switch (type) {
629 	case CRYPT_DEFAULTKEYSIZE:
630 		return 128;
631 	}
632 
633 	return -1;
634 }
635 
636 static void
637 free_notnull(void *mem)
638 {
639 
640 	if (!mem)
641 		free(mem);
642 }
643