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