1 #ifndef LINT 2 static const char rcsid[] = "$Header: /proj/cvs/prod/libbind/dst/dst_api.c,v 1.17 2007/09/24 17:18:25 each Exp $"; 3 #endif 4 5 /* 6 * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. 7 * 8 * Permission to use, copy modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS 13 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 15 * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, 16 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 17 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 18 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 19 * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. 20 */ 21 /* 22 * This file contains the interface between the DST API and the crypto API. 23 * This is the only file that needs to be changed if the crypto system is 24 * changed. Exported functions are: 25 * void dst_init() Initialize the toolkit 26 * int dst_check_algorithm() Function to determines if alg is suppored. 27 * int dst_compare_keys() Function to compare two keys for equality. 28 * int dst_sign_data() Incremental signing routine. 29 * int dst_verify_data() Incremental verify routine. 30 * int dst_generate_key() Function to generate new KEY 31 * DST_KEY *dst_read_key() Function to retrieve private/public KEY. 32 * void dst_write_key() Function to write out a key. 33 * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST 34 * KEY structure. 35 * int dst_key_to_dnskey() Function to return a public key in DNS 36 * format binary 37 * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY 38 * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer 39 * void dst_free_key() Releases all memory referenced by key structure 40 */ 41 42 #include "port_before.h" 43 #include <stdio.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <string.h> 49 #include <memory.h> 50 #include <ctype.h> 51 #include <time.h> 52 #include <sys/param.h> 53 #include <sys/stat.h> 54 #include <sys/socket.h> 55 #include <netinet/in.h> 56 #include <arpa/nameser.h> 57 #include <resolv.h> 58 59 #include "dst_internal.h" 60 #include "port_after.h" 61 62 /* static variables */ 63 static int done_init = 0; 64 dst_func *dst_t_func[DST_MAX_ALGS]; 65 const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n"; 66 const char *dst_path = ""; 67 68 /* internal I/O functions */ 69 static DST_KEY *dst_s_read_public_key(const char *in_name, 70 const u_int16_t in_id, int in_alg); 71 static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key, 72 u_int16_t in_id, int in_alg); 73 static int dst_s_write_public_key(const DST_KEY *key); 74 static int dst_s_write_private_key(const DST_KEY *key); 75 76 /* internal function to set up data structure */ 77 static DST_KEY *dst_s_get_key_struct(const char *name, const int alg, 78 const int flags, const int protocol, 79 const int bits); 80 81 /*% 82 * dst_init 83 * This function initializes the Digital Signature Toolkit. 84 * Right now, it just checks the DSTKEYPATH environment variable. 85 * Parameters 86 * none 87 * Returns 88 * none 89 */ 90 void 91 dst_init() 92 { 93 char *s; 94 int len; 95 96 if (done_init != 0) 97 return; 98 done_init = 1; 99 100 s = getenv("DSTKEYPATH"); 101 len = 0; 102 if (s) { 103 struct stat statbuf; 104 105 len = strlen(s); 106 if (len > PATH_MAX) { 107 EREPORT(("%s is longer than %d characters, ignoring\n", 108 s, PATH_MAX)); 109 } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { 110 EREPORT(("%s is not a valid directory\n", s)); 111 } else { 112 char *tmp; 113 tmp = (char *) malloc(len + 2); 114 memcpy(tmp, s, len + 1); 115 if (tmp[strlen(tmp) - 1] != '/') { 116 tmp[strlen(tmp) + 1] = 0; 117 tmp[strlen(tmp)] = '/'; 118 } 119 dst_path = tmp; 120 } 121 } 122 memset(dst_t_func, 0, sizeof(dst_t_func)); 123 /* first one is selected */ 124 dst_hmac_md5_init(); 125 } 126 127 /*% 128 * dst_check_algorithm 129 * This function determines if the crypto system for the specified 130 * algorithm is present. 131 * Parameters 132 * alg 1 KEY_RSA 133 * 3 KEY_DSA 134 * 157 KEY_HMAC_MD5 135 * future algorithms TBD and registered with IANA. 136 * Returns 137 * 1 - The algorithm is available. 138 * 0 - The algorithm is not available. 139 */ 140 int 141 dst_check_algorithm(const int alg) 142 { 143 return (dst_t_func[alg] != NULL); 144 } 145 146 /*% 147 * dst_s_get_key_struct 148 * This function allocates key structure and fills in some of the 149 * fields of the structure. 150 * Parameters: 151 * name: the name of the key 152 * alg: the algorithm number 153 * flags: the dns flags of the key 154 * protocol: the dns protocol of the key 155 * bits: the size of the key 156 * Returns: 157 * NULL if error 158 * valid pointer otherwise 159 */ 160 static DST_KEY * 161 dst_s_get_key_struct(const char *name, const int alg, const int flags, 162 const int protocol, const int bits) 163 { 164 DST_KEY *new_key = NULL; 165 166 if (dst_check_algorithm(alg)) /*%< make sure alg is available */ 167 new_key = (DST_KEY *) malloc(sizeof(*new_key)); 168 if (new_key == NULL) 169 return (NULL); 170 171 memset(new_key, 0, sizeof(*new_key)); 172 new_key->dk_key_name = strdup(name); 173 if (new_key->dk_key_name == NULL) { 174 free(new_key); 175 return (NULL); 176 } 177 new_key->dk_alg = alg; 178 new_key->dk_flags = flags; 179 new_key->dk_proto = protocol; 180 new_key->dk_KEY_struct = NULL; 181 new_key->dk_key_size = bits; 182 new_key->dk_func = dst_t_func[alg]; 183 return (new_key); 184 } 185 186 /*% 187 * dst_compare_keys 188 * Compares two keys for equality. 189 * Parameters 190 * key1, key2 Two keys to be compared. 191 * Returns 192 * 0 The keys are equal. 193 * non-zero The keys are not equal. 194 */ 195 196 int 197 dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2) 198 { 199 if (key1 == key2) 200 return (0); 201 if (key1 == NULL || key2 == NULL) 202 return (4); 203 if (key1->dk_alg != key2->dk_alg) 204 return (1); 205 if (key1->dk_key_size != key2->dk_key_size) 206 return (2); 207 if (key1->dk_id != key2->dk_id) 208 return (3); 209 return (key1->dk_func->compare(key1, key2)); 210 } 211 212 /*% 213 * dst_sign_data 214 * An incremental signing function. Data is signed in steps. 215 * First the context must be initialized (SIG_MODE_INIT). 216 * Then data is hashed (SIG_MODE_UPDATE). Finally the signature 217 * itself is created (SIG_MODE_FINAL). This function can be called 218 * once with INIT, UPDATE and FINAL modes all set, or it can be 219 * called separately with a different mode set for each step. The 220 * UPDATE step can be repeated. 221 * Parameters 222 * mode A bit mask used to specify operation(s) to be performed. 223 * SIG_MODE_INIT 1 Initialize digest 224 * SIG_MODE_UPDATE 2 Add data to digest 225 * SIG_MODE_FINAL 4 Generate signature 226 * from signature 227 * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL 228 * data Data to be signed. 229 * len The length in bytes of data to be signed. 230 * in_key Contains a private key to sign with. 231 * KEY structures should be handled (created, converted, 232 * compared, stored, freed) by the DST. 233 * signature 234 * The location to which the signature will be written. 235 * sig_len Length of the signature field in bytes. 236 * Return 237 * 0 Successfull INIT or Update operation 238 * >0 success FINAL (sign) operation 239 * <0 failure 240 */ 241 242 int 243 dst_sign_data(const int mode, DST_KEY *in_key, void **context, 244 const u_char *data, const int len, 245 u_char *signature, const int sig_len) 246 { 247 DUMP(data, mode, len, "dst_sign_data()"); 248 249 if (mode & SIG_MODE_FINAL && 250 (in_key->dk_KEY_struct == NULL || signature == NULL)) 251 return (MISSING_KEY_OR_SIGNATURE); 252 253 if (in_key->dk_func && in_key->dk_func->sign) 254 return (in_key->dk_func->sign(mode, in_key, context, data, len, 255 signature, sig_len)); 256 return (UNKNOWN_KEYALG); 257 } 258 259 /*% 260 * dst_verify_data 261 * An incremental verify function. Data is verified in steps. 262 * First the context must be initialized (SIG_MODE_INIT). 263 * Then data is hashed (SIG_MODE_UPDATE). Finally the signature 264 * is verified (SIG_MODE_FINAL). This function can be called 265 * once with INIT, UPDATE and FINAL modes all set, or it can be 266 * called separately with a different mode set for each step. The 267 * UPDATE step can be repeated. 268 * Parameters 269 * mode Operations to perform this time. 270 * SIG_MODE_INIT 1 Initialize digest 271 * SIG_MODE_UPDATE 2 add data to digest 272 * SIG_MODE_FINAL 4 verify signature 273 * SIG_MODE_ALL 274 * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL) 275 * data Data to pass through the hash function. 276 * len Length of the data in bytes. 277 * in_key Key for verification. 278 * signature Location of signature. 279 * sig_len Length of the signature in bytes. 280 * Returns 281 * 0 Verify success 282 * Non-Zero Verify Failure 283 */ 284 285 int 286 dst_verify_data(const int mode, DST_KEY *in_key, void **context, 287 const u_char *data, const int len, 288 const u_char *signature, const int sig_len) 289 { 290 DUMP(data, mode, len, "dst_verify_data()"); 291 if (mode & SIG_MODE_FINAL && 292 (in_key->dk_KEY_struct == NULL || signature == NULL)) 293 return (MISSING_KEY_OR_SIGNATURE); 294 295 if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL) 296 return (UNSUPPORTED_KEYALG); 297 return (in_key->dk_func->verify(mode, in_key, context, data, len, 298 signature, sig_len)); 299 } 300 301 /*% 302 * dst_read_private_key 303 * Access a private key. First the list of private keys that have 304 * already been read in is searched, then the key accessed on disk. 305 * If the private key can be found, it is returned. If the key cannot 306 * be found, a null pointer is returned. The options specify required 307 * key characteristics. If the private key requested does not have 308 * these characteristics, it will not be read. 309 * Parameters 310 * in_keyname The private key name. 311 * in_id The id of the private key. 312 * options DST_FORCE_READ Read from disk - don't use a previously 313 * read key. 314 * DST_CAN_SIGN The key must be useable for signing. 315 * DST_NO_AUTHEN The key must be useable for authentication. 316 * DST_STANDARD Return any key 317 * Returns 318 * NULL If there is no key found in the current directory or 319 * this key has not been loaded before. 320 * !NULL Success - KEY structure returned. 321 */ 322 323 DST_KEY * 324 dst_read_key(const char *in_keyname, const u_int16_t in_id, 325 const int in_alg, const int type) 326 { 327 char keyname[PATH_MAX]; 328 DST_KEY *dg_key = NULL, *pubkey = NULL; 329 330 if (!dst_check_algorithm(in_alg)) { /*%< make sure alg is available */ 331 EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n", 332 in_alg)); 333 return (NULL); 334 } 335 if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0) 336 return (NULL); 337 if (in_keyname == NULL) { 338 EREPORT(("dst_read_private_key(): Null key name passed in\n")); 339 return (NULL); 340 } else if (strlen(in_keyname) >= sizeof(keyname)) { 341 EREPORT(("dst_read_private_key(): keyname too big\n")); 342 return (NULL); 343 } else 344 strcpy(keyname, in_keyname); 345 346 /* before I read in the public key, check if it is allowed to sign */ 347 if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL) 348 return (NULL); 349 350 if (type == DST_PUBLIC) 351 return pubkey; 352 353 if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg, 354 pubkey->dk_flags, pubkey->dk_proto, 355 0))) 356 return (dg_key); 357 /* Fill in private key and some fields in the general key structure */ 358 if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id, 359 pubkey->dk_alg) == 0) 360 dg_key = dst_free_key(dg_key); 361 362 (void)dst_free_key(pubkey); 363 return (dg_key); 364 } 365 366 int 367 dst_write_key(const DST_KEY *key, const int type) 368 { 369 int pub = 0, priv = 0; 370 371 if (key == NULL) 372 return (0); 373 if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */ 374 EREPORT(("dst_write_key(): Algorithm %d not suppored\n", 375 key->dk_alg)); 376 return (UNSUPPORTED_KEYALG); 377 } 378 if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0) 379 return (0); 380 381 if (type & DST_PUBLIC) 382 if ((pub = dst_s_write_public_key(key)) < 0) 383 return (pub); 384 if (type & DST_PRIVATE) 385 if ((priv = dst_s_write_private_key(key)) < 0) 386 return (priv); 387 return (priv+pub); 388 } 389 390 /*% 391 * dst_write_private_key 392 * Write a private key to disk. The filename will be of the form: 393 * K<key->dk_name>+<key->dk_alg+><key-d>k_id.><private key suffix>. 394 * If there is already a file with this name, an error is returned. 395 * 396 * Parameters 397 * key A DST managed key structure that contains 398 * all information needed about a key. 399 * Return 400 * >= 0 Correct behavior. Returns length of encoded key value 401 * written to disk. 402 * < 0 error. 403 */ 404 405 static int 406 dst_s_write_private_key(const DST_KEY *key) 407 { 408 u_char encoded_block[RAW_KEY_SIZE]; 409 char file[PATH_MAX]; 410 int len; 411 FILE *fp; 412 413 /* First encode the key into the portable key format */ 414 if (key == NULL) 415 return (-1); 416 if (key->dk_KEY_struct == NULL) 417 return (0); /*%< null key has no private key */ 418 if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) { 419 EREPORT(("dst_write_private_key(): Unsupported operation %d\n", 420 key->dk_alg)); 421 return (-5); 422 } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block, 423 sizeof(encoded_block))) <= 0) { 424 EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len)); 425 return (-8); 426 } 427 /* Now I can create the file I want to use */ 428 dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg, 429 PRIVATE_KEY, PATH_MAX); 430 431 /* Do not overwrite an existing file */ 432 if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) { 433 int nn; 434 if ((nn = fwrite(encoded_block, 1, len, fp)) != len) { 435 EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n", 436 file, len, nn, errno)); 437 fclose(fp); 438 return (-5); 439 } 440 fclose(fp); 441 } else { 442 EREPORT(("dst_write_private_key(): Can not create file %s\n" 443 ,file)); 444 return (-6); 445 } 446 memset(encoded_block, 0, len); 447 return (len); 448 } 449 450 /*% 451 * 452 * dst_read_public_key 453 * Read a public key from disk and store in a DST key structure. 454 * Parameters 455 * in_name K<in_name><in_id>.<public key suffix> is the 456 * filename of the key file to be read. 457 * Returns 458 * NULL If the key does not exist or no name is supplied. 459 * NON-NULL Initialized key structure if the key exists. 460 */ 461 462 static DST_KEY * 463 dst_s_read_public_key(const char *in_name, const u_int16_t in_id, int in_alg) 464 { 465 int flags, proto, alg, len, dlen; 466 int c; 467 char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace; 468 u_char deckey[RAW_KEY_SIZE]; 469 FILE *fp; 470 471 if (in_name == NULL) { 472 EREPORT(("dst_read_public_key(): No key name given\n")); 473 return (NULL); 474 } 475 if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY, 476 PATH_MAX) == -1) { 477 EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n", 478 in_name, in_id, PUBLIC_KEY)); 479 return (NULL); 480 } 481 /* 482 * Open the file and read it's formatted contents up to key 483 * File format: 484 * domain.name [ttl] [IN] KEY <flags> <protocol> <algorithm> <key> 485 * flags, proto, alg stored as decimal (or hex numbers FIXME). 486 * (FIXME: handle parentheses for line continuation.) 487 */ 488 if ((fp = dst_s_fopen(name, "r", 0)) == NULL) { 489 EREPORT(("dst_read_public_key(): Public Key not found %s\n", 490 name)); 491 return (NULL); 492 } 493 /* Skip domain name, which ends at first blank */ 494 while ((c = getc(fp)) != EOF) 495 if (isspace(c)) 496 break; 497 /* Skip blank to get to next field */ 498 while ((c = getc(fp)) != EOF) 499 if (!isspace(c)) 500 break; 501 502 /* Skip optional TTL -- if initial digit, skip whole word. */ 503 if (isdigit(c)) { 504 while ((c = getc(fp)) != EOF) 505 if (isspace(c)) 506 break; 507 while ((c = getc(fp)) != EOF) 508 if (!isspace(c)) 509 break; 510 } 511 /* Skip optional "IN" */ 512 if (c == 'I' || c == 'i') { 513 while ((c = getc(fp)) != EOF) 514 if (isspace(c)) 515 break; 516 while ((c = getc(fp)) != EOF) 517 if (!isspace(c)) 518 break; 519 } 520 /* Locate and skip "KEY" */ 521 if (c != 'K' && c != 'k') { 522 EREPORT(("\"KEY\" doesn't appear in file: %s", name)); 523 return NULL; 524 } 525 while ((c = getc(fp)) != EOF) 526 if (isspace(c)) 527 break; 528 while ((c = getc(fp)) != EOF) 529 if (!isspace(c)) 530 break; 531 ungetc(c, fp); /*%< return the charcter to the input field */ 532 /* Handle hex!! FIXME. */ 533 534 if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) { 535 EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n" 536 ,name)); 537 return (NULL); 538 } 539 /* read in the key string */ 540 fgets(enckey, sizeof(enckey), fp); 541 542 /* If we aren't at end-of-file, something is wrong. */ 543 while ((c = getc(fp)) != EOF) 544 if (!isspace(c)) 545 break; 546 if (!feof(fp)) { 547 EREPORT(("Key too long in file: %s", name)); 548 return NULL; 549 } 550 fclose(fp); 551 552 if ((len = strlen(enckey)) <= 0) 553 return (NULL); 554 555 /* discard \n */ 556 enckey[--len] = '\0'; 557 558 /* remove leading spaces */ 559 for (notspace = (char *) enckey; isspace((*notspace)&0xff); len--) 560 notspace++; 561 562 dlen = b64_pton(notspace, deckey, sizeof(deckey)); 563 if (dlen < 0) { 564 EREPORT(("dst_read_public_key: bad return from b64_pton = %d", 565 dlen)); 566 return (NULL); 567 } 568 /* store key and info in a key structure that is returned */ 569 /* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey, 570 dlen);*/ 571 return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen); 572 } 573 574 /*% 575 * dst_write_public_key 576 * Write a key to disk in DNS format. 577 * Parameters 578 * key Pointer to a DST key structure. 579 * Returns 580 * 0 Failure 581 * 1 Success 582 */ 583 584 static int 585 dst_s_write_public_key(const DST_KEY *key) 586 { 587 FILE *fp; 588 char filename[PATH_MAX]; 589 u_char out_key[RAW_KEY_SIZE]; 590 char enc_key[RAW_KEY_SIZE]; 591 int len = 0; 592 int mode; 593 594 memset(out_key, 0, sizeof(out_key)); 595 if (key == NULL) { 596 EREPORT(("dst_write_public_key(): No key specified \n")); 597 return (0); 598 } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0) 599 return (0); 600 601 /* Make the filename */ 602 if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id, 603 key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) { 604 EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n", 605 key->dk_key_name, key->dk_id, PUBLIC_KEY)); 606 return (0); 607 } 608 /* XXX in general this should be a check for symmetric keys */ 609 mode = (key->dk_alg == KEY_HMAC_MD5) ? 0600 : 0644; 610 /* create public key file */ 611 if ((fp = dst_s_fopen(filename, "w+", mode)) == NULL) { 612 EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n", 613 filename, errno)); 614 return (0); 615 } 616 /*write out key first base64 the key data */ 617 if (key->dk_flags & DST_EXTEND_FLAG) 618 b64_ntop(&out_key[6], len - 6, enc_key, sizeof(enc_key)); 619 else 620 b64_ntop(&out_key[4], len - 4, enc_key, sizeof(enc_key)); 621 fprintf(fp, "%s IN KEY %d %d %d %s\n", 622 key->dk_key_name, 623 key->dk_flags, key->dk_proto, key->dk_alg, enc_key); 624 fclose(fp); 625 return (1); 626 } 627 628 /*% 629 * dst_dnskey_to_public_key 630 * This function converts the contents of a DNS KEY RR into a DST 631 * key structure. 632 * Paramters 633 * len Length of the RDATA of the KEY RR RDATA 634 * rdata A pointer to the the KEY RR RDATA. 635 * in_name Key name to be stored in key structure. 636 * Returns 637 * NULL Failure 638 * NON-NULL Success. Pointer to key structure. 639 * Caller's responsibility to free() it. 640 */ 641 642 DST_KEY * 643 dst_dnskey_to_key(const char *in_name, const u_char *rdata, const int len) 644 { 645 DST_KEY *key_st; 646 int alg ; 647 int start = DST_KEY_START; 648 649 if (rdata == NULL || len <= DST_KEY_ALG) /*%< no data */ 650 return (NULL); 651 alg = (u_int8_t) rdata[DST_KEY_ALG]; 652 if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */ 653 EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n", 654 alg)); 655 return (NULL); 656 } 657 658 if (in_name == NULL) 659 return (NULL); 660 661 if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL) 662 return (NULL); 663 664 key_st->dk_id = dst_s_dns_key_id(rdata, len); 665 key_st->dk_flags = dst_s_get_int16(rdata); 666 key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT]; 667 if (key_st->dk_flags & DST_EXTEND_FLAG) { 668 u_int32_t ext_flags; 669 ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]); 670 key_st->dk_flags = key_st->dk_flags | (ext_flags << 16); 671 start += 2; 672 } 673 /* 674 * now point to the begining of the data representing the encoding 675 * of the key 676 */ 677 if (key_st->dk_func && key_st->dk_func->from_dns_key) { 678 if (key_st->dk_func->from_dns_key(key_st, &rdata[start], 679 len - start) > 0) 680 return (key_st); 681 } else 682 EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n", 683 alg)); 684 685 SAFE_FREE(key_st); 686 return (key_st); 687 } 688 689 /*% 690 * dst_public_key_to_dnskey 691 * Function to encode a public key into DNS KEY wire format 692 * Parameters 693 * key Key structure to encode. 694 * out_storage Location to write the encoded key to. 695 * out_len Size of the output array. 696 * Returns 697 * <0 Failure 698 * >=0 Number of bytes written to out_storage 699 */ 700 701 int 702 dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage, 703 const int out_len) 704 { 705 u_int16_t val; 706 int loc = 0; 707 int enc_len = 0; 708 if (key == NULL) 709 return (-1); 710 711 if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */ 712 EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n", 713 key->dk_alg)); 714 return (UNSUPPORTED_KEYALG); 715 } 716 memset(out_storage, 0, out_len); 717 val = (u_int16_t)(key->dk_flags & 0xffff); 718 dst_s_put_int16(out_storage, val); 719 loc += 2; 720 721 out_storage[loc++] = (u_char) key->dk_proto; 722 out_storage[loc++] = (u_char) key->dk_alg; 723 724 if (key->dk_flags > 0xffff) { /*%< Extended flags */ 725 val = (u_int16_t)((key->dk_flags >> 16) & 0xffff); 726 dst_s_put_int16(&out_storage[loc], val); 727 loc += 2; 728 } 729 if (key->dk_KEY_struct == NULL) 730 return (loc); 731 if (key->dk_func && key->dk_func->to_dns_key) { 732 enc_len = key->dk_func->to_dns_key(key, 733 (u_char *) &out_storage[loc], 734 out_len - loc); 735 if (enc_len > 0) 736 return (enc_len + loc); 737 else 738 return (-1); 739 } else 740 EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n", 741 key->dk_alg)); 742 return (-1); 743 } 744 745 /*% 746 * dst_buffer_to_key 747 * Function to encode a string of raw data into a DST key 748 * Parameters 749 * alg The algorithm (HMAC only) 750 * key A pointer to the data 751 * keylen The length of the data 752 * Returns 753 * NULL an error occurred 754 * NON-NULL the DST key 755 */ 756 DST_KEY * 757 dst_buffer_to_key(const char *key_name, /*!< name of the key */ 758 const int alg, /*!< algorithm */ 759 const int flags, /*!< dns flags */ 760 const int protocol, /*!< dns protocol */ 761 const u_char *key_buf, /*!< key in dns wire fmt */ 762 const int key_len) /*!< size of key */ 763 { 764 765 DST_KEY *dkey = NULL; 766 int dnslen; 767 u_char dns[2048]; 768 769 if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */ 770 EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg)); 771 return (NULL); 772 } 773 774 dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1); 775 776 if (dkey == NULL || dkey->dk_func == NULL || 777 dkey->dk_func->from_dns_key == NULL) 778 return (dst_free_key(dkey)); 779 780 if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) { 781 EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n")); 782 return (dst_free_key(dkey)); 783 } 784 785 dnslen = dst_key_to_dnskey(dkey, dns, sizeof(dns)); 786 dkey->dk_id = dst_s_dns_key_id(dns, dnslen); 787 return (dkey); 788 } 789 790 int 791 dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len) 792 { 793 int len; 794 /* this function will extrac the secret of HMAC into a buffer */ 795 if (key == NULL) 796 return (0); 797 if (key->dk_func != NULL && key->dk_func->to_dns_key != NULL) { 798 len = key->dk_func->to_dns_key(key, out_buff, buf_len); 799 if (len < 0) 800 return (0); 801 return (len); 802 } 803 return (0); 804 } 805 806 /*% 807 * dst_s_read_private_key_file 808 * Function reads in private key from a file. 809 * Fills out the KEY structure. 810 * Parameters 811 * name Name of the key to be read. 812 * pk_key Structure that the key is returned in. 813 * in_id Key identifier (tag) 814 * Return 815 * 1 if everthing works 816 * 0 if there is any problem 817 */ 818 819 static int 820 dst_s_read_private_key_file(char *name, DST_KEY *pk_key, u_int16_t in_id, 821 int in_alg) 822 { 823 int cnt, alg, len, major, minor, file_major, file_minor; 824 int ret, id; 825 char filename[PATH_MAX]; 826 u_char in_buff[RAW_KEY_SIZE], *p; 827 FILE *fp; 828 int dnslen; 829 u_char dns[2048]; 830 831 if (name == NULL || pk_key == NULL) { 832 EREPORT(("dst_read_private_key_file(): No key name given\n")); 833 return (0); 834 } 835 /* Make the filename */ 836 if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY, 837 PATH_MAX) == -1) { 838 EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n", 839 name, in_id, PRIVATE_KEY)); 840 return (0); 841 } 842 /* first check if we can find the key file */ 843 if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) { 844 EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n", 845 filename, dst_path[0] ? dst_path : 846 (char *) getcwd(NULL, PATH_MAX - 1))); 847 return (0); 848 } 849 /* now read the header info from the file */ 850 if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) { 851 fclose(fp); 852 EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n", 853 filename)); 854 return (0); 855 } 856 /* decrypt key */ 857 fclose(fp); 858 if (memcmp(in_buff, "Private-key-format: v", 20) != 0) 859 goto fail; 860 len = cnt; 861 p = in_buff; 862 863 if (!dst_s_verify_str((const char **) (void *)&p, 864 "Private-key-format: v")) { 865 EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name)); 866 goto fail; 867 } 868 /* read in file format */ 869 sscanf((char *)p, "%d.%d", &file_major, &file_minor); 870 sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor); 871 if (file_major < 1) { 872 EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n", 873 file_major, file_minor, name)); 874 goto fail; 875 } else if (file_major > major || file_minor > minor) 876 EREPORT(( 877 "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n", 878 name, file_major, file_minor)); 879 880 while (*p++ != '\n') ; /*%< skip to end of line */ 881 882 if (!dst_s_verify_str((const char **) (void *)&p, "Algorithm: ")) 883 goto fail; 884 885 if (sscanf((char *)p, "%d", &alg) != 1) 886 goto fail; 887 while (*p++ != '\n') ; /*%< skip to end of line */ 888 889 if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name)) 890 SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name)); 891 pk_key->dk_key_name = (char *) strdup(name); 892 893 /* allocate and fill in key structure */ 894 if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL) 895 goto fail; 896 897 ret = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, &in_buff[len] - p); 898 if (ret < 0) 899 goto fail; 900 901 dnslen = dst_key_to_dnskey(pk_key, dns, sizeof(dns)); 902 id = dst_s_dns_key_id(dns, dnslen); 903 904 /* Make sure the actual key tag matches the input tag used in the filename 905 */ 906 if (id != in_id) { 907 EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id)); 908 goto fail; 909 } 910 pk_key->dk_id = (u_int16_t) id; 911 pk_key->dk_alg = alg; 912 memset(in_buff, 0, cnt); 913 return (1); 914 915 fail: 916 memset(in_buff, 0, cnt); 917 return (0); 918 } 919 920 /*% 921 * Generate and store a public/private keypair. 922 * Keys will be stored in formatted files. 923 * 924 * Parameters 925 & 926 *\par name Name of the new key. Used to create key files 927 *\li K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private. 928 *\par bits Size of the new key in bits. 929 *\par exp What exponent to use: 930 *\li 0 use exponent 3 931 *\li non-zero use Fermant4 932 *\par flags The default value of the DNS Key flags. 933 *\li The DNS Key RR Flag field is defined in RFC2065, 934 * section 3.3. The field has 16 bits. 935 *\par protocol 936 *\li Default value of the DNS Key protocol field. 937 *\li The DNS Key protocol field is defined in RFC2065, 938 * section 3.4. The field has 8 bits. 939 *\par alg What algorithm to use. Currently defined: 940 *\li KEY_RSA 1 941 *\li KEY_DSA 3 942 *\li KEY_HMAC 157 943 *\par out_id The key tag is returned. 944 * 945 * Return 946 *\li NULL Failure 947 *\li non-NULL the generated key pair 948 * Caller frees the result, and its dk_name pointer. 949 */ 950 DST_KEY * 951 dst_generate_key(const char *name, const int bits, const int exp, 952 const int flags, const int protocol, const int alg) 953 { 954 DST_KEY *new_key = NULL; 955 int dnslen; 956 u_char dns[2048]; 957 958 if (name == NULL) 959 return (NULL); 960 961 if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */ 962 EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg)); 963 return (NULL); 964 } 965 966 new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits); 967 if (new_key == NULL) 968 return (NULL); 969 if (bits == 0) /*%< null key we are done */ 970 return (new_key); 971 if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) { 972 EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n", 973 alg)); 974 return (dst_free_key(new_key)); 975 } 976 if (new_key->dk_func->generate(new_key, exp) <= 0) { 977 EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n", 978 new_key->dk_key_name, new_key->dk_alg, 979 new_key->dk_key_size, exp)); 980 return (dst_free_key(new_key)); 981 } 982 983 dnslen = dst_key_to_dnskey(new_key, dns, sizeof(dns)); 984 if (dnslen != UNSUPPORTED_KEYALG) 985 new_key->dk_id = dst_s_dns_key_id(dns, dnslen); 986 else 987 new_key->dk_id = 0; 988 989 return (new_key); 990 } 991 992 /*% 993 * Release all data structures pointed to by a key structure. 994 * 995 * Parameters 996 *\li f_key Key structure to be freed. 997 */ 998 999 DST_KEY * 1000 dst_free_key(DST_KEY *f_key) 1001 { 1002 1003 if (f_key == NULL) 1004 return (f_key); 1005 if (f_key->dk_func && f_key->dk_func->destroy) 1006 f_key->dk_KEY_struct = 1007 f_key->dk_func->destroy(f_key->dk_KEY_struct); 1008 else { 1009 EREPORT(("dst_free_key(): Unknown key alg %d\n", 1010 f_key->dk_alg)); 1011 } 1012 if (f_key->dk_KEY_struct) { 1013 free(f_key->dk_KEY_struct); 1014 f_key->dk_KEY_struct = NULL; 1015 } 1016 if (f_key->dk_key_name) 1017 SAFE_FREE(f_key->dk_key_name); 1018 SAFE_FREE(f_key); 1019 return (NULL); 1020 } 1021 1022 /*% 1023 * Return the maximim size of signature from the key specified in bytes 1024 * 1025 * Parameters 1026 *\li key 1027 * 1028 * Returns 1029 * \li bytes 1030 */ 1031 int 1032 dst_sig_size(DST_KEY *key) { 1033 switch (key->dk_alg) { 1034 case KEY_HMAC_MD5: 1035 return (16); 1036 case KEY_HMAC_SHA1: 1037 return (20); 1038 case KEY_RSA: 1039 return (key->dk_key_size + 7) / 8; 1040 case KEY_DSA: 1041 return (40); 1042 default: 1043 EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg)); 1044 return -1; 1045 } 1046 } 1047 1048 /*! \file */ 1049