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