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