1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #include <stdio.h> 29*7c478bd9Sstevel@tonic-gate #include <ctype.h> 30*7c478bd9Sstevel@tonic-gate #include <unistd.h> 31*7c478bd9Sstevel@tonic-gate #include <strings.h> 32*7c478bd9Sstevel@tonic-gate #include <libintl.h> 33*7c478bd9Sstevel@tonic-gate #include <locale.h> 34*7c478bd9Sstevel@tonic-gate #include <limits.h> 35*7c478bd9Sstevel@tonic-gate #include <libgen.h> 36*7c478bd9Sstevel@tonic-gate #include <errno.h> 37*7c478bd9Sstevel@tonic-gate #include <assert.h> 38*7c478bd9Sstevel@tonic-gate #include <wanbootutil.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/wanboot_impl.h> 44*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 45*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* Return codes */ 48*7c478bd9Sstevel@tonic-gate #define KEYGEN_SUCCESS 0 49*7c478bd9Sstevel@tonic-gate #define KEYGEN_ERROR 1 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* Defaults */ 52*7c478bd9Sstevel@tonic-gate static char default_net[] = "0.0.0.0"; 53*7c478bd9Sstevel@tonic-gate static char default_cid[] = "00000000000000"; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate /* Suboption. */ 56*7c478bd9Sstevel@tonic-gate #define NET 0 57*7c478bd9Sstevel@tonic-gate #define CID 1 58*7c478bd9Sstevel@tonic-gate #define TYPE 2 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate static char *opts[] = { "net", "cid", "type", NULL }; 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* 63*7c478bd9Sstevel@tonic-gate * This routine is used to parse the suboptions of '-o' option. 64*7c478bd9Sstevel@tonic-gate * 65*7c478bd9Sstevel@tonic-gate * The option should be of the form: 66*7c478bd9Sstevel@tonic-gate * net=<addr>,cid=<cid>,type=<3des|aes|sha1|rsa> 67*7c478bd9Sstevel@tonic-gate * 68*7c478bd9Sstevel@tonic-gate * This routine will pass the values of each of the suboptions back in the 69*7c478bd9Sstevel@tonic-gate * supplied arguments, 'net', 'cid' and 'ka'. 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * Returns: 72*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate static int 75*7c478bd9Sstevel@tonic-gate process_option(char *arg, char **net, char **cid, wbku_key_attr_t *ka) 76*7c478bd9Sstevel@tonic-gate { 77*7c478bd9Sstevel@tonic-gate char *value; 78*7c478bd9Sstevel@tonic-gate wbku_retcode_t ret; 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate while (*arg != '\0') { 81*7c478bd9Sstevel@tonic-gate switch (getsubopt(&arg, opts, &value)) { 82*7c478bd9Sstevel@tonic-gate case NET: 83*7c478bd9Sstevel@tonic-gate /* 84*7c478bd9Sstevel@tonic-gate * Network number. 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate *net = value; 87*7c478bd9Sstevel@tonic-gate break; 88*7c478bd9Sstevel@tonic-gate case CID: 89*7c478bd9Sstevel@tonic-gate /* 90*7c478bd9Sstevel@tonic-gate * Client ID. 91*7c478bd9Sstevel@tonic-gate */ 92*7c478bd9Sstevel@tonic-gate *cid = value; 93*7c478bd9Sstevel@tonic-gate break; 94*7c478bd9Sstevel@tonic-gate case TYPE: 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * Key type. 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate ret = wbku_str_to_keyattr(value, ka, WBKU_ANY_KEY); 99*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS) { 100*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 101*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate break; 104*7c478bd9Sstevel@tonic-gate default: 105*7c478bd9Sstevel@tonic-gate wbku_printerr("%s is not a valid option\n", value); 106*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* 111*7c478bd9Sstevel@tonic-gate * Sanity checks 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate if (*net != NULL && **net == '\0') { 114*7c478bd9Sstevel@tonic-gate wbku_printerr("Missing net option value\n"); 115*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate if (*cid != NULL && **cid == '\0') { 118*7c478bd9Sstevel@tonic-gate wbku_printerr("Missing cid option value\n"); 119*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate if (*cid != NULL && *net == NULL) { 122*7c478bd9Sstevel@tonic-gate wbku_printerr( 123*7c478bd9Sstevel@tonic-gate "The cid option requires net option specification\n"); 124*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate if (ka->ka_type == WBKU_KEY_UNKNOWN) { 127*7c478bd9Sstevel@tonic-gate wbku_printerr("Missing key type option value\n"); 128*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate /* 135*7c478bd9Sstevel@tonic-gate * This routine parses a buffer to determine whether or not it 136*7c478bd9Sstevel@tonic-gate * contains a hexascii string. If the buffer contains any characters 137*7c478bd9Sstevel@tonic-gate * that are not hexascii, then it is not a hexascii string. Since 138*7c478bd9Sstevel@tonic-gate * this function is used to validate a CID value (which is then used 139*7c478bd9Sstevel@tonic-gate * to identify a directory in the filesystem), no evaluation of the 140*7c478bd9Sstevel@tonic-gate * string is performed. That is, hex strings are not padded (e.g. "A" 141*7c478bd9Sstevel@tonic-gate * is not padded to "0A"). 142*7c478bd9Sstevel@tonic-gate * 143*7c478bd9Sstevel@tonic-gate * Returns: 144*7c478bd9Sstevel@tonic-gate * B_TRUE or B_FALSE 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate static boolean_t 147*7c478bd9Sstevel@tonic-gate isxstring(const char *buf) 148*7c478bd9Sstevel@tonic-gate { 149*7c478bd9Sstevel@tonic-gate if ((strlen(buf) % 2) != 0) { 150*7c478bd9Sstevel@tonic-gate return (B_FALSE); 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate for (; *buf != '\0'; ++buf) { 154*7c478bd9Sstevel@tonic-gate if (!isxdigit(*buf)) { 155*7c478bd9Sstevel@tonic-gate return (B_FALSE); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate return (B_TRUE); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate /* 162*7c478bd9Sstevel@tonic-gate * This routine uses the 'net' and the 'cid' to generate the client's 163*7c478bd9Sstevel@tonic-gate * keystore filename and, if requested, creates the directory path to 164*7c478bd9Sstevel@tonic-gate * the file if any of the directories do not exist. If directory path 165*7c478bd9Sstevel@tonic-gate * creation is not requested and any of the directories do not exist, 166*7c478bd9Sstevel@tonic-gate * then an error is returned. 167*7c478bd9Sstevel@tonic-gate * 168*7c478bd9Sstevel@tonic-gate * Returns: 169*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 170*7c478bd9Sstevel@tonic-gate */ 171*7c478bd9Sstevel@tonic-gate static int 172*7c478bd9Sstevel@tonic-gate create_client_filename(char *filename, size_t len, const char *net, 173*7c478bd9Sstevel@tonic-gate const char *cid, boolean_t create) 174*7c478bd9Sstevel@tonic-gate { 175*7c478bd9Sstevel@tonic-gate struct in_addr addr; 176*7c478bd9Sstevel@tonic-gate size_t size; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate if (net == NULL) { 179*7c478bd9Sstevel@tonic-gate size = snprintf(filename, len, "%s", CLIENT_KEY_DIR); 180*7c478bd9Sstevel@tonic-gate } else if (inet_pton(AF_INET, net, &addr) != 1) { 181*7c478bd9Sstevel@tonic-gate wbku_printerr("%s is not a valid network address\n", net); 182*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 183*7c478bd9Sstevel@tonic-gate } else if (cid == NULL) { 184*7c478bd9Sstevel@tonic-gate size = snprintf(filename, len, "%s/%s", CLIENT_KEY_DIR, net); 185*7c478bd9Sstevel@tonic-gate } else if (!isxstring(cid)) { 186*7c478bd9Sstevel@tonic-gate wbku_printerr( 187*7c478bd9Sstevel@tonic-gate "%s must be an even number of hexadecimal characters\n", 188*7c478bd9Sstevel@tonic-gate cid); 189*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 190*7c478bd9Sstevel@tonic-gate } else { 191*7c478bd9Sstevel@tonic-gate size = snprintf(filename, len, "%s/%s/%s", CLIENT_KEY_DIR, 192*7c478bd9Sstevel@tonic-gate net, cid); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * Shouldn't be a problem, but make sure buffer was big enough. 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate if (size >= len) { 199*7c478bd9Sstevel@tonic-gate wbku_printerr("Keystore path too long\n"); 200*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * If directory creation is allowed, then try to create it. 205*7c478bd9Sstevel@tonic-gate * If the directory already exists, then march on. 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate if (create) { 208*7c478bd9Sstevel@tonic-gate if (mkdirp(filename, S_IRWXU) == -1 && errno != EEXIST) { 209*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot create client keystore"); 210*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate /* 215*7c478bd9Sstevel@tonic-gate * Append the filename. 216*7c478bd9Sstevel@tonic-gate */ 217*7c478bd9Sstevel@tonic-gate if (strlcat(filename, "/keystore", len) >= len) { 218*7c478bd9Sstevel@tonic-gate wbku_printerr("Keystore path too long\n"); 219*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * This routine generates a random key of the type defined by 'ka'. 227*7c478bd9Sstevel@tonic-gate * The key value is returned in 'rand_key' and the buffer pointed to 228*7c478bd9Sstevel@tonic-gate * by 'rand_key' is assumed to be of the correct size. 229*7c478bd9Sstevel@tonic-gate * 230*7c478bd9Sstevel@tonic-gate * Note: 231*7c478bd9Sstevel@tonic-gate * If 'ka' has a non-NULL keycheck value, then the routine will 232*7c478bd9Sstevel@tonic-gate * generate randon keys until a non-weak key is generated. 233*7c478bd9Sstevel@tonic-gate * 234*7c478bd9Sstevel@tonic-gate * Returns: 235*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate static int 238*7c478bd9Sstevel@tonic-gate gen_key(const wbku_key_attr_t *ka, uint8_t *rand_key) 239*7c478bd9Sstevel@tonic-gate { 240*7c478bd9Sstevel@tonic-gate /* 241*7c478bd9Sstevel@tonic-gate * Generate key, until non-weak key generated. 242*7c478bd9Sstevel@tonic-gate */ 243*7c478bd9Sstevel@tonic-gate for (;;) { 244*7c478bd9Sstevel@tonic-gate if (wbio_nread_rand(rand_key, ka->ka_len) != 0) { 245*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot generate random number"); 246*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (ka->ka_keycheck == NULL || ka->ka_keycheck(rand_key)) { 250*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate } 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate /* 256*7c478bd9Sstevel@tonic-gate * This routine generates a random master key of the type (currently only 257*7c478bd9Sstevel@tonic-gate * HMAC SHA1 supported) defined by 'ka' and stores it in the master key 258*7c478bd9Sstevel@tonic-gate * file. 259*7c478bd9Sstevel@tonic-gate * 260*7c478bd9Sstevel@tonic-gate * Returns: 261*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 262*7c478bd9Sstevel@tonic-gate */ 263*7c478bd9Sstevel@tonic-gate static int 264*7c478bd9Sstevel@tonic-gate master_gen_key(wbku_key_attr_t *ka) 265*7c478bd9Sstevel@tonic-gate { 266*7c478bd9Sstevel@tonic-gate uint8_t mas_key[WANBOOT_HMAC_KEY_SIZE]; 267*7c478bd9Sstevel@tonic-gate int fd; 268*7c478bd9Sstevel@tonic-gate FILE *fp = NULL; 269*7c478bd9Sstevel@tonic-gate fpos_t pos; 270*7c478bd9Sstevel@tonic-gate wbku_retcode_t ret; 271*7c478bd9Sstevel@tonic-gate boolean_t exists = B_FALSE; 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* 274*7c478bd9Sstevel@tonic-gate * If the file already exists (possibly via keymgmt), then open 275*7c478bd9Sstevel@tonic-gate * the file for update. Otherwise create it and open it for 276*7c478bd9Sstevel@tonic-gate * for writing. 277*7c478bd9Sstevel@tonic-gate */ 278*7c478bd9Sstevel@tonic-gate fd = open(MASTER_KEY_FILE, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); 279*7c478bd9Sstevel@tonic-gate if (fd < 0) { 280*7c478bd9Sstevel@tonic-gate if (errno == EEXIST) { 281*7c478bd9Sstevel@tonic-gate fp = fopen(MASTER_KEY_FILE, "r+"); 282*7c478bd9Sstevel@tonic-gate exists = B_TRUE; 283*7c478bd9Sstevel@tonic-gate } 284*7c478bd9Sstevel@tonic-gate } else { 285*7c478bd9Sstevel@tonic-gate if ((fp = fdopen(fd, "w")) == NULL) { 286*7c478bd9Sstevel@tonic-gate (void) close(fd); 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 291*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot open master keystore", MASTER_KEY_FILE); 292*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * If the file already exists, then see if a master key already 297*7c478bd9Sstevel@tonic-gate * exists. We will not overwrite it if it does. 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate ret = WBKU_NOKEY; 300*7c478bd9Sstevel@tonic-gate if (exists) { 301*7c478bd9Sstevel@tonic-gate ret = wbku_find_key(fp, NULL, ka, NULL, B_TRUE); 302*7c478bd9Sstevel@tonic-gate if (ret != WBKU_NOKEY) { 303*7c478bd9Sstevel@tonic-gate if (ret == WBKU_SUCCESS) { 304*7c478bd9Sstevel@tonic-gate wbku_printerr("The master %s key already " 305*7c478bd9Sstevel@tonic-gate "exists and will not be overwritten\n", 306*7c478bd9Sstevel@tonic-gate ka->ka_str); 307*7c478bd9Sstevel@tonic-gate } else { 308*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 311*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * If wbku_find_key() did not find the key position for us 317*7c478bd9Sstevel@tonic-gate * (expected behavior), then we should set position to 318*7c478bd9Sstevel@tonic-gate * the end of the file. 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate if (ret == WBKU_NOKEY && 321*7c478bd9Sstevel@tonic-gate (fseek(fp, 0, SEEK_END) != 0 || fgetpos(fp, &pos) != 0)) { 322*7c478bd9Sstevel@tonic-gate wbku_printerr("Internal error"); 323*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 324*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * Generate a key and write it. 329*7c478bd9Sstevel@tonic-gate */ 330*7c478bd9Sstevel@tonic-gate if (gen_key(ka, mas_key) != KEYGEN_SUCCESS) { 331*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 332*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate ret = wbku_write_key(fp, &pos, ka, mas_key, B_TRUE); 336*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 337*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS) { 338*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 339*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate (void) printf(gettext("The master %s key has been generated\n"), 343*7c478bd9Sstevel@tonic-gate ka->ka_str); 344*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * This routine generates a random client key of the type 349*7c478bd9Sstevel@tonic-gate * defined by 'ka' and stores it in the client keystore. 350*7c478bd9Sstevel@tonic-gate * file. 351*7c478bd9Sstevel@tonic-gate * 352*7c478bd9Sstevel@tonic-gate * Returns: 353*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 354*7c478bd9Sstevel@tonic-gate */ 355*7c478bd9Sstevel@tonic-gate static int 356*7c478bd9Sstevel@tonic-gate client_gen_key(const char *filename, wbku_key_attr_t *ka, const char *net, 357*7c478bd9Sstevel@tonic-gate const char *cid) 358*7c478bd9Sstevel@tonic-gate { 359*7c478bd9Sstevel@tonic-gate int fd; 360*7c478bd9Sstevel@tonic-gate FILE *cli_fp = NULL; 361*7c478bd9Sstevel@tonic-gate FILE *mas_fp; 362*7c478bd9Sstevel@tonic-gate fpos_t pos; 363*7c478bd9Sstevel@tonic-gate uint8_t cli_key[WANBOOT_MAXKEYLEN]; 364*7c478bd9Sstevel@tonic-gate uint8_t mas_key[WANBOOT_HMAC_KEY_SIZE]; 365*7c478bd9Sstevel@tonic-gate SHA1_CTX ctx; 366*7c478bd9Sstevel@tonic-gate char cid_buf[PATH_MAX]; 367*7c478bd9Sstevel@tonic-gate boolean_t exists = B_FALSE; 368*7c478bd9Sstevel@tonic-gate wbku_retcode_t ret; 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate /* 371*7c478bd9Sstevel@tonic-gate * If the file already exists (possibly via keymgmt), then open 372*7c478bd9Sstevel@tonic-gate * the file for update. Otherwise create it and open it for 373*7c478bd9Sstevel@tonic-gate * for writing. 374*7c478bd9Sstevel@tonic-gate */ 375*7c478bd9Sstevel@tonic-gate fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); 376*7c478bd9Sstevel@tonic-gate if (fd < 0) { 377*7c478bd9Sstevel@tonic-gate if (errno == EEXIST) { 378*7c478bd9Sstevel@tonic-gate cli_fp = fopen(filename, "r+"); 379*7c478bd9Sstevel@tonic-gate exists = B_TRUE; 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate } else { 382*7c478bd9Sstevel@tonic-gate if ((cli_fp = fdopen(fd, "w")) == NULL) { 383*7c478bd9Sstevel@tonic-gate (void) close(fd); 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate if (cli_fp == NULL) { 388*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot open client keystore"); 389*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate /* 393*7c478bd9Sstevel@tonic-gate * Generate the key. Encryption keys can be generated by simply 394*7c478bd9Sstevel@tonic-gate * calling gen_key(). An HMAC SHA1 key will be generated by 395*7c478bd9Sstevel@tonic-gate * hashing the master key. 396*7c478bd9Sstevel@tonic-gate */ 397*7c478bd9Sstevel@tonic-gate switch (ka->ka_type) { 398*7c478bd9Sstevel@tonic-gate case WBKU_KEY_3DES: 399*7c478bd9Sstevel@tonic-gate case WBKU_KEY_AES_128: 400*7c478bd9Sstevel@tonic-gate if (gen_key(ka, cli_key) != KEYGEN_SUCCESS) { 401*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 402*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate break; 405*7c478bd9Sstevel@tonic-gate case WBKU_KEY_HMAC_SHA1: 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * Follow RFC 3118 Appendix A's algorithm to generate 408*7c478bd9Sstevel@tonic-gate * the HMAC/SHA1 client key. 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * Open the master keystore for reading only. 413*7c478bd9Sstevel@tonic-gate */ 414*7c478bd9Sstevel@tonic-gate if ((mas_fp = fopen(MASTER_KEY_FILE, "r")) == NULL) { 415*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot open master keystore"); 416*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 417*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate /* 421*7c478bd9Sstevel@tonic-gate * Find the master key. 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate ret = wbku_find_key(mas_fp, NULL, ka, mas_key, B_TRUE); 424*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS) { 425*7c478bd9Sstevel@tonic-gate if (ret == WBKU_NOKEY) { 426*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot create a client key " 427*7c478bd9Sstevel@tonic-gate "without first creating a master key\n"); 428*7c478bd9Sstevel@tonic-gate } else { 429*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate (void) fclose(mas_fp); 432*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 433*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate (void) fclose(mas_fp); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate /* 438*7c478bd9Sstevel@tonic-gate * Now generate the client's unique ID buffer. 439*7c478bd9Sstevel@tonic-gate */ 440*7c478bd9Sstevel@tonic-gate if (strlcpy(cid_buf, net, PATH_MAX) >= PATH_MAX || 441*7c478bd9Sstevel@tonic-gate strlcat(cid_buf, cid, PATH_MAX) >= PATH_MAX) { 442*7c478bd9Sstevel@tonic-gate wbku_printerr("Unique id for client is too big\n"); 443*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 444*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * Hash the buffer to create the client key. 449*7c478bd9Sstevel@tonic-gate */ 450*7c478bd9Sstevel@tonic-gate HMACInit(&ctx, mas_key, WANBOOT_HMAC_KEY_SIZE); 451*7c478bd9Sstevel@tonic-gate HMACUpdate(&ctx, (uint8_t *)cid_buf, strlen(cid_buf)); 452*7c478bd9Sstevel@tonic-gate HMACFinal(&ctx, mas_key, WANBOOT_HMAC_KEY_SIZE, cli_key); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate break; 455*7c478bd9Sstevel@tonic-gate case WBKU_KEY_RSA: 456*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot generate RSA key using keygen\n"); 457*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 458*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 459*7c478bd9Sstevel@tonic-gate default: 460*7c478bd9Sstevel@tonic-gate wbku_printerr("Internal error\n"); 461*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 462*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate /* 466*7c478bd9Sstevel@tonic-gate * Look to see if a client key of this type exists and if 467*7c478bd9Sstevel@tonic-gate * it does note its position in the file. 468*7c478bd9Sstevel@tonic-gate */ 469*7c478bd9Sstevel@tonic-gate ret = WBKU_NOKEY; 470*7c478bd9Sstevel@tonic-gate if (exists) { 471*7c478bd9Sstevel@tonic-gate ret = wbku_find_key(cli_fp, &pos, ka, NULL, B_FALSE); 472*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS && ret != WBKU_NOKEY) { 473*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 474*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 475*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate /* 480*7c478bd9Sstevel@tonic-gate * If wbku_find_key() did not find the key position for us, 481*7c478bd9Sstevel@tonic-gate * then we should set position to the end of the file. 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate if (ret == WBKU_NOKEY && 484*7c478bd9Sstevel@tonic-gate (fseek(cli_fp, 0, SEEK_END) != 0 || fgetpos(cli_fp, &pos) != 0)) { 485*7c478bd9Sstevel@tonic-gate wbku_printerr("Internal error"); 486*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 487*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate /* 491*7c478bd9Sstevel@tonic-gate * Write the key. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate ret = wbku_write_key(cli_fp, &pos, ka, cli_key, B_FALSE); 494*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS) { 495*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 496*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 497*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate (void) fclose(cli_fp); 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate (void) printf(gettext("A new client %s key has been generated\n"), 502*7c478bd9Sstevel@tonic-gate ka->ka_str); 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * This routine is used to print a hexascii version of a key. 509*7c478bd9Sstevel@tonic-gate * The hexascii version of the key will be twice the length 510*7c478bd9Sstevel@tonic-gate * of 'datalen'. 511*7c478bd9Sstevel@tonic-gate */ 512*7c478bd9Sstevel@tonic-gate static void 513*7c478bd9Sstevel@tonic-gate keydump(const char *key, int keylen) 514*7c478bd9Sstevel@tonic-gate { 515*7c478bd9Sstevel@tonic-gate uint16_t *p16; 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate assert(IS_P2ALIGNED(key, sizeof (uint16_t))); 518*7c478bd9Sstevel@tonic-gate /*LINTED aligned*/ 519*7c478bd9Sstevel@tonic-gate for (p16 = (uint16_t *)key; keylen > 0; keylen -= 2) { 520*7c478bd9Sstevel@tonic-gate (void) printf("%04x", htons(*p16++)); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * This routine is used to print a key of the type 527*7c478bd9Sstevel@tonic-gate * described by 'ka'. If 'master' is true, then the 528*7c478bd9Sstevel@tonic-gate * key to display is the master key. Otherwise, it's a 529*7c478bd9Sstevel@tonic-gate * client key. 530*7c478bd9Sstevel@tonic-gate * 531*7c478bd9Sstevel@tonic-gate * Returns: 532*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 533*7c478bd9Sstevel@tonic-gate */ 534*7c478bd9Sstevel@tonic-gate static int 535*7c478bd9Sstevel@tonic-gate display_key(const char *filename, wbku_key_attr_t *ka, boolean_t master) 536*7c478bd9Sstevel@tonic-gate { 537*7c478bd9Sstevel@tonic-gate uint8_t key[WANBOOT_MAXKEYLEN]; 538*7c478bd9Sstevel@tonic-gate FILE *fp; 539*7c478bd9Sstevel@tonic-gate wbku_retcode_t ret; 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate /* 542*7c478bd9Sstevel@tonic-gate * Open the keystore for reading only. 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) { 545*7c478bd9Sstevel@tonic-gate wbku_printerr("Cannot open keystore"); 546*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate /* 550*7c478bd9Sstevel@tonic-gate * Find the key. 551*7c478bd9Sstevel@tonic-gate */ 552*7c478bd9Sstevel@tonic-gate ret = wbku_find_key(fp, NULL, ka, key, master); 553*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS) { 554*7c478bd9Sstevel@tonic-gate if (ret == WBKU_NOKEY) { 555*7c478bd9Sstevel@tonic-gate wbku_printerr("The %s %s key does not exist\n", 556*7c478bd9Sstevel@tonic-gate (master ? "master" : "client"), ka->ka_str); 557*7c478bd9Sstevel@tonic-gate } else { 558*7c478bd9Sstevel@tonic-gate wbku_printerr("%s\n", wbku_retmsg(ret)); 559*7c478bd9Sstevel@tonic-gate } 560*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 561*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate /* 566*7c478bd9Sstevel@tonic-gate * Dump the key in hex. 567*7c478bd9Sstevel@tonic-gate */ 568*7c478bd9Sstevel@tonic-gate keydump((char *)key, ka->ka_len); 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * Prints usage(). 575*7c478bd9Sstevel@tonic-gate */ 576*7c478bd9Sstevel@tonic-gate static void 577*7c478bd9Sstevel@tonic-gate usage(const char *cmd) 578*7c478bd9Sstevel@tonic-gate { 579*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Usage: %s [-m | -c " 580*7c478bd9Sstevel@tonic-gate "-o net=<addr>,cid=<cid>,type=<%s|%s|%s>]\n" 581*7c478bd9Sstevel@tonic-gate " %s -d [-m | -c -o net=<addr>,cid=<cid>," 582*7c478bd9Sstevel@tonic-gate "type=<%s|%s|%s|%s>]\n"), 583*7c478bd9Sstevel@tonic-gate cmd, WBKU_KW_3DES, WBKU_KW_AES_128, WBKU_KW_HMAC_SHA1, 584*7c478bd9Sstevel@tonic-gate cmd, WBKU_KW_3DES, WBKU_KW_AES_128, WBKU_KW_HMAC_SHA1, WBKU_KW_RSA); 585*7c478bd9Sstevel@tonic-gate } 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate /* 588*7c478bd9Sstevel@tonic-gate * This program is used to generate and display WAN boot encryption and 589*7c478bd9Sstevel@tonic-gate * hash keys. The paths to the keystores are predetermined. That is, the 590*7c478bd9Sstevel@tonic-gate * master keystore (used to store a master HMAC SHA1 key) will always 591*7c478bd9Sstevel@tonic-gate * reside in the default location, MASTER_KEY_FILE. The client keystores 592*7c478bd9Sstevel@tonic-gate * will always reside in default locations that are computed using their 593*7c478bd9Sstevel@tonic-gate * network number and cid values. 594*7c478bd9Sstevel@tonic-gate * 595*7c478bd9Sstevel@tonic-gate * Note: 596*7c478bd9Sstevel@tonic-gate * The master keystore can store client keys too. This program 597*7c478bd9Sstevel@tonic-gate * cannot be used to insert client keys into the master keystore. 598*7c478bd9Sstevel@tonic-gate * However, it must not corrupt any client keystore inserted into 599*7c478bd9Sstevel@tonic-gate * the file by other means (keymgmt). 600*7c478bd9Sstevel@tonic-gate * 601*7c478bd9Sstevel@tonic-gate * We do not do any file locking scheme. This means that if two 602*7c478bd9Sstevel@tonic-gate * keygen commands are run concurrently, results can be disastrous. 603*7c478bd9Sstevel@tonic-gate * 604*7c478bd9Sstevel@tonic-gate * Returns: 605*7c478bd9Sstevel@tonic-gate * KEYGEN_SUCCESS or KEYGEN_ERROR. 606*7c478bd9Sstevel@tonic-gate */ 607*7c478bd9Sstevel@tonic-gate int 608*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 609*7c478bd9Sstevel@tonic-gate { 610*7c478bd9Sstevel@tonic-gate char filename[PATH_MAX]; 611*7c478bd9Sstevel@tonic-gate char *filenamep; 612*7c478bd9Sstevel@tonic-gate int c; 613*7c478bd9Sstevel@tonic-gate boolean_t is_client = B_FALSE; 614*7c478bd9Sstevel@tonic-gate boolean_t is_master = B_FALSE; 615*7c478bd9Sstevel@tonic-gate boolean_t display = B_FALSE; 616*7c478bd9Sstevel@tonic-gate char *net = NULL; 617*7c478bd9Sstevel@tonic-gate char *cid = NULL; 618*7c478bd9Sstevel@tonic-gate wbku_key_attr_t ka; 619*7c478bd9Sstevel@tonic-gate wbku_retcode_t ret; 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate /* 622*7c478bd9Sstevel@tonic-gate * Do the necessary magic for localization support. 623*7c478bd9Sstevel@tonic-gate */ 624*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 625*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 626*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 627*7c478bd9Sstevel@tonic-gate #endif 628*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate /* 631*7c478bd9Sstevel@tonic-gate * Initialize program name for use by wbku_printerr(). 632*7c478bd9Sstevel@tonic-gate */ 633*7c478bd9Sstevel@tonic-gate wbku_errinit(argv[0]); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate /* 636*7c478bd9Sstevel@tonic-gate * At the very least, we'll need one arg. 637*7c478bd9Sstevel@tonic-gate */ 638*7c478bd9Sstevel@tonic-gate if (argc < 2) { 639*7c478bd9Sstevel@tonic-gate usage(argv[0]); 640*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * Parse the options. 645*7c478bd9Sstevel@tonic-gate */ 646*7c478bd9Sstevel@tonic-gate ka.ka_type = WBKU_KEY_UNKNOWN; 647*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "dcmo:")) != EOF) { 648*7c478bd9Sstevel@tonic-gate switch (c) { 649*7c478bd9Sstevel@tonic-gate case 'd': 650*7c478bd9Sstevel@tonic-gate /* 651*7c478bd9Sstevel@tonic-gate * Display a key. 652*7c478bd9Sstevel@tonic-gate */ 653*7c478bd9Sstevel@tonic-gate display = B_TRUE; 654*7c478bd9Sstevel@tonic-gate break; 655*7c478bd9Sstevel@tonic-gate case 'o': 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * Suboptions. 658*7c478bd9Sstevel@tonic-gate */ 659*7c478bd9Sstevel@tonic-gate if (process_option(optarg, &net, &cid, &ka) != 0) { 660*7c478bd9Sstevel@tonic-gate usage(argv[0]); 661*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate break; 664*7c478bd9Sstevel@tonic-gate case 'c': 665*7c478bd9Sstevel@tonic-gate is_client = B_TRUE; 666*7c478bd9Sstevel@tonic-gate break; 667*7c478bd9Sstevel@tonic-gate case 'm': 668*7c478bd9Sstevel@tonic-gate is_master = B_TRUE; 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate default: 671*7c478bd9Sstevel@tonic-gate usage(argv[0]); 672*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * Must be operating on a master or client key and if 678*7c478bd9Sstevel@tonic-gate * it's a client key, then type must have been given. 679*7c478bd9Sstevel@tonic-gate */ 680*7c478bd9Sstevel@tonic-gate if ((is_client == is_master) || 681*7c478bd9Sstevel@tonic-gate (is_client && ka.ka_type == WBKU_KEY_UNKNOWN)) { 682*7c478bd9Sstevel@tonic-gate usage(argv[0]); 683*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate /* 687*7c478bd9Sstevel@tonic-gate * If operating on the master key, then it is an HMAC SHA1 688*7c478bd9Sstevel@tonic-gate * key. Build the correct 'ka'. If we're working on a client 689*7c478bd9Sstevel@tonic-gate * key, the 'ka' was already built as part of option parsing. 690*7c478bd9Sstevel@tonic-gate */ 691*7c478bd9Sstevel@tonic-gate if (is_master) { 692*7c478bd9Sstevel@tonic-gate ret = wbku_str_to_keyattr(WBKU_KW_HMAC_SHA1, &ka, 693*7c478bd9Sstevel@tonic-gate WBKU_HASH_KEY); 694*7c478bd9Sstevel@tonic-gate if (ret != WBKU_SUCCESS) { 695*7c478bd9Sstevel@tonic-gate wbku_printerr("Internal error\n"); 696*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate filenamep = MASTER_KEY_FILE; 699*7c478bd9Sstevel@tonic-gate } else { 700*7c478bd9Sstevel@tonic-gate /* 701*7c478bd9Sstevel@tonic-gate * Build the path to the client keystore. 702*7c478bd9Sstevel@tonic-gate */ 703*7c478bd9Sstevel@tonic-gate if (create_client_filename(filename, sizeof (filename), net, 704*7c478bd9Sstevel@tonic-gate cid, !display) != KEYGEN_SUCCESS) { 705*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate filenamep = filename; 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate /* 711*7c478bd9Sstevel@tonic-gate * If display chosen, go do it. 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate if (display) { 714*7c478bd9Sstevel@tonic-gate return (display_key(filenamep, &ka, is_master)); 715*7c478bd9Sstevel@tonic-gate } 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate /* 718*7c478bd9Sstevel@tonic-gate * Can't generate RSA key here. 719*7c478bd9Sstevel@tonic-gate */ 720*7c478bd9Sstevel@tonic-gate if (ka.ka_type == WBKU_KEY_RSA) { 721*7c478bd9Sstevel@tonic-gate wbku_printerr("keygen cannot create RSA key\n"); 722*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate /* 726*7c478bd9Sstevel@tonic-gate * If generating a master key, go do it. 727*7c478bd9Sstevel@tonic-gate */ 728*7c478bd9Sstevel@tonic-gate if (is_master) { 729*7c478bd9Sstevel@tonic-gate return (master_gen_key(&ka)); 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * Must be generating a client key, go do it. 734*7c478bd9Sstevel@tonic-gate */ 735*7c478bd9Sstevel@tonic-gate if (net == NULL) { 736*7c478bd9Sstevel@tonic-gate net = default_net; 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate if (cid == NULL) { 739*7c478bd9Sstevel@tonic-gate cid = default_cid; 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate if (client_gen_key(filename, &ka, net, cid) != KEYGEN_SUCCESS) { 742*7c478bd9Sstevel@tonic-gate return (KEYGEN_ERROR); 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate return (KEYGEN_SUCCESS); 746*7c478bd9Sstevel@tonic-gate } 747