xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/wanboot/keygen/keygen.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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