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