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