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