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