xref: /titanic_52/usr/src/cmd/cmd-crypto/pktool/pktool.c (revision 93a6f655de601ef9f8e8bfeca1b816fbfca6bc17)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file comprises the main driver for this tool.
30  * Upon parsing the command verbs from user input, it
31  * branches to the appropriate modules to perform the
32  * requested task.
33  */
34 
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <malloc.h>
39 #include <libgen.h>
40 #include <errno.h>
41 #include <cryptoutil.h>
42 #include <security/cryptoki.h>
43 #include "common.h"
44 
45 /*
46  * The verbcmd construct allows genericizing information about a verb so
47  * that it is easier to manipulate.  Makes parsing code easier to read,
48  * fix, and extend with new verbs.
49  */
50 typedef struct verbcmd_s {
51 	char	*verb;
52 	int	(*action)(int, char *[]);
53 	int	mode;
54 	char	*synopsis;
55 } verbcmd;
56 
57 /* External declarations for supported verb actions. */
58 extern int	pk_setpin(int argc, char *argv[]);
59 extern int	pk_list(int argc, char *argv[]);
60 extern int	pk_delete(int argc, char *argv[]);
61 extern int	pk_import(int argc, char *argv[]);
62 extern int	pk_export(int argc, char *argv[]);
63 extern int	pk_tokens(int argc, char *argv[]);
64 extern int	pk_gencert(int argc, char *argv[]);
65 extern int	pk_gencsr(int argc, char *argv[]);
66 extern int	pk_download(int argc, char *argv[]);
67 extern int	pk_genkey(int argc, char *argv[]);
68 
69 /* Forward declarations for "built-in" verb actions. */
70 static int	pk_help(int argc, char *argv[]);
71 
72 /* Command structure for verbs and their actions.  Do NOT i18n/l10n. */
73 static verbcmd	cmds[] = {
74 	{ "tokens",	pk_tokens,	0,	"tokens" },
75 	{ "setpin",	pk_setpin,	0,
76 		"setpin [ keystore=pkcs11 ]\n\t\t"
77 		"[ token=token[:manuf[:serial]]]\n\t"
78 
79 		"setpin keystore=nss\n\t\t"
80 		"[ token=token ]\n\t\t"
81 		"[ dir=directory-path ]\n\t\t"
82 		"[ prefix=DBprefix ]\n\t"
83 	},
84 	{ "list",	pk_list,	0,
85 
86 	"list [ token=token[:manuf[:serial]]]\n\t\t"
87 		"[ objtype=private|public|both ]\n\t\t"
88 		"[ label=label ]\n\t"
89 
90 	"list objtype=cert[:[public | private | both ]]\n\t\t"
91 		"[ subject=subject-DN ]\n\t\t"
92 		"[ keystore=pkcs11 ]\n\t\t"
93 		"[ issuer=issuer-DN ]\n\t\t"
94 		"[ serial=serial number]\n\t\t"
95 		"[ label=cert-label ]\n\t\t"
96 		"[ token=token[:manuf[:serial]]]\n\t\t"
97 		"[ criteria=valid|expired|both ]\n\t"
98 
99 	"list objtype=key[:[public | private | both ]]\n\t\t"
100 		"[ keystore=pkcs11 ]\n\t\t"
101 		"[ subject=subject-DN ]\n\t\t"
102 		"[ label=key-label ]\n\t\t"
103 		"[ token=token[:manuf[:serial]]]\n\t"
104 
105 	"list keystore=pkcs11 objtype=crl\n\t\t"
106 		"infile=crl-fn\n\t\t"
107 		"[ dir=directory-path ]\n\t"
108 
109 	"list keystore=nss objtype=cert\n\t\t"
110 		"[ subject=subject-DN ]\n\t\t"
111 		"[ issuer=issuer-DN ]\n\t\t"
112 		"[ serial=serial number]\n\t\t"
113 		"[ nickname=cert-nickname ]\n\t\t"
114 		"[ token=token[:manuf[:serial]]]\n\t\t"
115 		"[ dir=directory-path ]\n\t\t"
116 		"[ prefix=DBprefix ]\n\t\t"
117 		"[ criteria=valid|expired|both ]\n\t"
118 
119 	"list keystore=nss objtype=key\n\t\t"
120 		"[ token=token[:manuf[:serial]]]\n\t\t"
121 		"[ dir=directory-path ]\n\t\t"
122 		"[ prefix=DBprefix ]\n\t\t"
123 		"[ nickname=key-nickname ]\n\t"
124 
125 	"list keystore=file objtype=cert\n\t\t"
126 		"[ subject=subject-DN ]\n\t\t"
127 		"[ issuer=issuer-DN ]\n\t\t"
128 		"[ serial=serial number]\n\t\t"
129 		"[ infile=cert-fn ]\n\t\t"
130 		"[ dir=directory-path ]\n\t\t"
131 		"[ criteria=valid|expired|both ]\n\t"
132 
133 	"list keystore=file objtype=key\n\t\t"
134 		"[ infile=key-fn ]\n\t\t"
135 		"[ dir=directory-path ]\n\t"
136 
137 	"list keystore=file objtype=crl\n\t\t"
138 		"infile=crl-fn\n\t\t"
139 		"[ dir=directory-path ]\n\t"
140 	},
141 
142 	{ "delete",	pk_delete,	0,
143 
144 	"delete [ token=token[:manuf[:serial]]]\n\t\t"
145 		"[ objtype=private|public|both ]\n\t\t"
146 		"[ label=object-label ]\n\t"
147 
148 	"delete keystore=nss objtype=cert\n\t\t"
149 		"[ subject=subject-DN ]\n\t\t"
150 		"[ issuer=issuer-DN ]\n\t\t"
151 		"[ serial=serial number]\n\t\t"
152 		"[ nickname=cert-nickname ]\n\t\t"
153 		"[ token=token[:manuf[:serial]]]\n\t\t"
154 		"[ dir=directory-path ]\n\t\t"
155 		"[ prefix=DBprefix ]\n\t\t"
156 		"[ criteria=valid|expired|both ]\n\t"
157 
158 	"delete keystore=nss objtype=key\n\t\t"
159 		"[ token=token[:manuf[:serial]]]\n\t\t"
160 		"[ dir=directory-path ]\n\t\t"
161 		"[ prefix=DBprefix ]\n\t\t"
162 		"[ nickname=key-nickname ]\n\t\t"
163 
164 	"delete keystore=nss objtype=crl\n\t\t"
165 		"[ nickname=issuer-nickname ]\n\t\t"
166 		"[ subject=subject-DN ]\n\t\t"
167 		"[ token=token[:manuf[:serial]]]\n\t\t"
168 		"[ dir=directory-path ]\n\t\t"
169 		"[ prefix=DBprefix ]\n\t"
170 
171 	"delete keystore=pkcs11 objtype=cert[:[public | private | both]]\n\t\t"
172 		"[ subject=subject-DN ]\n\t\t"
173 		"[ issuer=issuer-DN ]\n\t\t"
174 		"[ serial=serial number]\n\t\t"
175 		"[ label=cert-label ]\n\t\t"
176 		"[ token=token[:manuf[:serial]]]\n\t\t"
177 		"[ criteria=valid|expired|both ]\n\t"
178 
179 	"delete keystore=pkcs11 objtype=key[:[public | private | both]]\n\t\t"
180 		"[ subject=subject-DN ]\n\t\t"
181 		"[ label=key-label ]\n\t\t"
182 		"[ token=token[:manuf[:serial]]]\n\t"
183 
184 	"delete keystore=pkcs11 objtype=crl\n\t\t"
185 		"infile=crl-fn\n\t\t"
186 		"[ dir=directory-path ]\n\t"
187 
188 	"delete keystore=file objtype=cert\n\t\t"
189 		"[ subject=subject-DN ]\n\t\t"
190 		"[ issuer=issuer-DN ]\n\t\t"
191 		"[ serial=serial number]\n\t\t"
192 		"[ infile=cert-fn ]\n\t\t"
193 		"[ dir=directory-path ]\n\t\t"
194 		"[ criteria=valid|expired|both ]\n\t"
195 
196 	"delete keystore=file objtype=key\n\t\t"
197 		"[ infile=key-fn ]\n\t\t"
198 		"[ dir=directory-path ]\n\t"
199 
200 	"delete keystore=file objtype=crl\n\t\t"
201 		"infile=crl-fn\n\t\t"
202 		"[ dir=directory-path ]\n\t"
203 	},
204 	{ "import",	pk_import,	0,
205 
206 	"import [token=token[:manuf[:serial]]]\n\t\t"
207 	"infile=input-fn\n\t"
208 
209 	"import keystore=nss objtype=cert\n\t\t"
210 		"infile=input-fn\n\t\t"
211 		"nickname=cert-nickname\n\t\t"
212 		"[ trust=trust-value ]\n\t\t"
213 		"[ token=token[:manuf[:serial]]]\n\t\t"
214 		"[ dir=directory-path ]\n\t\t"
215 		"[ prefix=DBprefix ]\n\t"
216 
217 	"import keystore=nss objtype=crl\n\t\t"
218 		"infile=input-fn\n\t\t"
219 		"[ verifycrl=y|n ]\n\t\t"
220 		"[ token=token[:manuf[:serial]]]\n\t\t"
221 		"[ dir=directory-path ]\n\t\t"
222 		"[ prefix=DBprefix ]\n\t"
223 
224 	"import keystore=pkcs11\n\t\t"
225 		"infile=input-fn\n\t\t"
226 		"label=cert-label\n\t\t"
227 		"[ token=token[:manuf[:serial]]]\n\t"
228 
229 	"import keystore=pkcs11 objtype=crl\n\t\t"
230 		"infile=input-crl-fn\n\t\t"
231 		"outcrl=output-crl-fn\n\t\t"
232 		"outformat=pem|der\n\t\t"
233 		"[ dir=output-crl-directory-path ]\n\t"
234 
235 	"import keystore=file\n\t\t"
236 		"infile=input-fn\n\t\t"
237 		"outkey=output-key-fn\n\t\t"
238 		"outcert=output-cert-fn\n\t\t"
239 		"[ dir=output-cert-dir-path ]\n\t\t"
240 		"[ keydir=output-key-dir-path ]\n\t\t"
241 		"[ outformat=pem|der|pkcs12 ]\n\t"
242 
243 	"import keystore=file objtype=crl\n\t\t"
244 		"infile=input-crl-fn\n\t\t"
245 		"outcrl=output-crl-fn\n\t\t"
246 		"outformat=pem|der\n\t\t"
247 		"[ dir=output-crl-directory-path ]\n\t"
248 	},
249 
250 	{ "export",	pk_export,	0,
251 
252 	"export [token=token[:manuf[:serial]]]\n\t\t"
253 	"outfile=output-fn\n\t"
254 
255 	"export keystore=nss\n\t\t"
256 		"outfile=output-fn\n\t\t"
257 		"[ objtype=cert|key ]\n\t\t"
258 		"[ subject=subject-DN ]\n\t\t"
259 		"[ issuer=issuer-DN ]\n\t\t"
260 		"[ serial=serial number]\n\t\t"
261 		"[ nickname=cert-nickname]\n\t\t"
262 		"[ token=token[:manuf[:serial]]]\n\t\t"
263 		"[ dir=directory-path ]\n\t\t"
264 		"[ prefix=DBPrefix ]\n\t\t"
265 		"[ outformat=pem|der|pkcs12 ]\n\t"
266 
267 	"export keystore=pkcs11\n\t\t"
268 		"outfile=output-fn\n\t\t"
269 		"[ label=cert-label]\n\t\t"
270 		"[ subject=subject-DN ]\n\t\t"
271 		"[ issuer=issuer-DN ]\n\t\t"
272 		"[ serial=serial number]\n\t\t"
273 		"[ outformat=pem|der|pkcs12]\n\t\t"
274 		"[ token=token[:manuf[:serial]]]\n\t"
275 
276 	"export keystore=file\n\t\t"
277 		"certfile=cert-input-fn\n\t\t"
278 		"keyfile=key-input-fn\n\t\t"
279 		"outfile=output-pkcs12-fn\n\t\t"
280 		"[ dir=directory-path ]\n\t"
281 	},
282 
283 	{ "gencert",	pk_gencert,	0,
284 	"gencert [-i] keystore=nss\n\t\t"
285 		"label=cert-nickname\n\t\t"
286 		"serial=serial number hex string]\n\t\t"
287 		"subject=subject-DN\n\t\t"
288 		"[ altname=[critical:]SubjectAltName ]\n\t\t"
289 		"[ keyusage=[critical:]usage,usage,...]\n\t\t"
290 		"[ token=token[:manuf[:serial]]]\n\t\t"
291 		"[ dir=directory-path ]\n\t\t"
292 		"[ prefix=DBprefix ]\n\t\t"
293 		"[ keytype=rsa|dsa ]\n\t\t"
294 		"[ keylen=key-size ]\n\t\t"
295 		"[ trust=trust-value ]\n\t\t"
296 		"[ lifetime=number-hour|number-day|number-year ]\n\t"
297 
298 	"gencert [-i] [ keystore=pkcs11 ]\n\t\t"
299 		"label=key/cert-label\n\t\t"
300 		"subject=subject-DN\n\t\t"
301 		"serial=serial number hex string\n\t\t"
302 		"[ altname=[critical:]SubjectAltName ]\n\t\t"
303 		"[ keyusage=[critical:]usage,usage,...]\n\t\t"
304 		"[ token=token[:manuf[:serial]]]\n\t\t"
305 		"[ keytype=rsa|dsa ]\n\t\t"
306 		"[ keylen=key-size ]\n\t\t"
307 		"[ lifetime=number-hour|number-day|number-year ]\n\t"
308 
309 	"gencert [-i] keystore=file\n\t\t"
310 		"outcert=cert_filename\n\t\t"
311 		"outkey=key_filename\n\t\t"
312 		"subject=subject-DN\n\t\t"
313 		"serial=serial number hex string\n\t\t"
314 		"[ altname=[critical:]SubjectAltName ]\n\t\t"
315 		"[ keyusage=[critical:]usage,usage,...]\n\t\t"
316 		"[ format=der|pem ]\n\t\t"
317 		"[ dir=directory-path ]\n\t\t"
318 		"[ prefix=DBprefix ]\n\t\t"
319 		"[ keytype=rsa|dsa ]\n\t\t"
320 		"[ keylen=key-size ]\n\t\t"
321 		"[ lifetime=number-hour|number-day|number-year ]\n\t"
322 	},
323 	{ "gencsr",	pk_gencsr,	0,
324 	"gencsr [-i] keystore=nss \n\t\t"
325 		"nickname=cert-nickname\n\t\t"
326 		"outcsr=csr-fn\n\t\t"
327 		"subject=subject-DN\n\t\t"
328 		"[ altname=[critical:]SubjectAltName ]\n\t\t"
329 		"[ keyusage=[critical:]usage,usage,...]\n\t\t"
330 		"[ token=token[:manuf[:serial]]]\n\t\t"
331 		"[ dir=directory-path ]\n\t\t"
332 		"[ prefix=DBprefix ]\n\t\t"
333 		"[ keytype=rsa|dsa ]\n\t\t"
334 		"[ keylen=key-size ]\n\t\t"
335 		"[ format=pem|der]\n\t"
336 	"gencsr [-i] [ keystore=pkcs11 ]\n\t\t"
337 		"label=key-label\n\t\t"
338 		"outcsr=csr-fn\n\t\t"
339 		"subject=subject-DN\n\t\t"
340 		"[ altname=[critical:]SubjectAltName ]\n\t\t"
341 		"[ keyusage=[critical:]usage,usage,...]\n\t\t"
342 		"[ token=token[:manuf[:serial]]]\n\t\t"
343 		"[ keytype=rsa|dsa ]\n\t\t"
344 		"[ keylen=key-size ]\n\t\t"
345 		"[ format=pem|der]\n\t"
346 	"gencsr [-i] keystore=file\n\t\t"
347 		"outcsr=csr-fn\n\t\t"
348 		"outkey=key-fn\n\t\t"
349 		"subject=subject-DN\n\t\t"
350 		"[ altname=[critical:]SubjectAltName ]\n\t\t"
351 		"[ keyusage=[critical:]usage,usage,...]\n\t\t"
352 		"[ keytype=rsa|dsa ]\n\t\t"
353 		"[ keylen=key-size ]\n\t\t"
354 		"[ dir=directory-path ]\n\t\t"
355 		"[ format=pem|der]\n\t"
356 	},
357 
358 	{ "download",	pk_download,	0,
359 	"download url=url_str\n\t\t"
360 		"[ objtype=crl|cert ]\n\t\t"
361 		"[ http_proxy=proxy_str ]\n\t\t"
362 		"[ outfile = outfile ]\n\t\t"
363 	},
364 
365 	{ "genkey",	pk_genkey,	0,
366 	"genkey [ keystore=pkcs11 ]\n\t\t"
367 		"label=key-label\n\t\t"
368 		"[ keytype=aes|arcfour|des|3des ]\n\t\t"
369 		"[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
370 		"[ token=token[:manuf[:serial]]]\n\t\t"
371 		"[ sensitive=y|n ]\n\t\t"
372 		"[ extractable=y|n ]\n\t\t"
373 		"[ print=y|n ]\n\t"
374 
375 	"genkey keystore=nss\n\t\t"
376 		"label=key-label\n\t\t"
377 		"[ keytype=aes|arcfour|des|3des ]\n\t\t"
378 		"[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
379 		"[ token=token[:manuf[:serial]]]\n\t\t"
380 		"[ dir=directory-path ]\n\t\t"
381 		"[ prefix=DBprefix ]\n\t"
382 
383 	"genkey keystore=file\n\t\t"
384 		"outkey=key-fn\n\t\t"
385 		"[ keytype=aes|arcfour|des|3des ]\n\t\t"
386 		"[ keylen=key-size (AES or ARCFOUR only)]\n\t\t"
387 		"[ dir=directory-path ]\n\t\t"
388 		"[ print=y|n ]\n\t"
389 	},
390 
391 	{ "-?",	pk_help,	0,	"help\t(help and usage)" },
392 	{ "-f",	pk_help,	0,	"-f option_file" }
393 };
394 static int	num_cmds = sizeof (cmds) / sizeof (verbcmd);
395 
396 static char	*prog;
397 static void	usage(int);
398 
399 /*
400  * Usage information.  This function must be updated when new verbs or
401  * options are added.
402  */
403 static void
404 usage(int idx)
405 {
406 	int	i;
407 
408 	/* Display this block only in command-line mode. */
409 	(void) fprintf(stdout, gettext("Usage:\n"));
410 	(void) fprintf(stdout, gettext("\t%s -?\t(help and usage)\n"), prog);
411 	(void) fprintf(stdout, gettext("\t%s -f option_file\n"), prog);
412 	(void) fprintf(stdout, gettext("\t%s subcommand [options...]\n"), prog);
413 	(void) fprintf(stdout, gettext("where subcommands may be:\n"));
414 
415 	/* Display only those verbs that match the current tool mode. */
416 	if (idx == -1) {
417 		for (i = 0; i < num_cmds; i++) {
418 			/* Do NOT i18n/l10n. */
419 			(void) fprintf(stdout, "\t%s\n", cmds[i].synopsis);
420 		}
421 	} else {
422 		(void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis);
423 	}
424 }
425 
426 /*
427  * Provide help, in the form of displaying the usage.
428  */
429 static int
430 pk_help(int argc, char *argv[])
431 /* ARGSUSED */
432 {
433 	usage(-1);
434 	return (0);
435 }
436 
437 /*
438  * Process arguments from the argfile and create a new
439  * argv/argc list to be processed later.
440  */
441 static int
442 process_arg_file(char *argfile, char ***argv, int *argc)
443 {
444 	FILE *fp;
445 	char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */
446 	char *p;
447 	int nargs = 0;
448 
449 	if ((fp = fopen(argfile, "rF")) == NULL) {
450 		(void) fprintf(stderr,
451 			gettext("Cannot read argfile %s: %s\n"),
452 			argfile, strerror(errno));
453 		return (errno);
454 	}
455 
456 	while (fgets(argline, sizeof (argline), fp) != NULL) {
457 		int j;
458 		/* remove trailing whitespace */
459 		j = strlen(argline) - 1;
460 		while (j >= 0 && isspace(argline[j])) {
461 			argline[j] = 0;
462 			j--;
463 		}
464 		/* If it was a blank line, get the next one. */
465 		if (!strlen(argline))
466 			continue;
467 
468 		(*argv) = realloc((*argv),
469 			(nargs + 1) * sizeof (char *));
470 		if ((*argv) == NULL) {
471 			perror("memory error");
472 			(void) fclose(fp);
473 			return (errno);
474 		}
475 		p = (char *)strdup(argline);
476 		if (p == NULL) {
477 			perror("memory error");
478 			(void) fclose(fp);
479 			return (errno);
480 		}
481 		(*argv)[nargs] = p;
482 		nargs++;
483 	}
484 	*argc = nargs;
485 	(void) fclose(fp);
486 	return (0);
487 }
488 
489 /*
490  * MAIN() -- where all the action is
491  */
492 int
493 main(int argc, char *argv[], char *envp[])
494 /* ARGSUSED2 */
495 {
496 	int	i, found = -1;
497 	int	rv;
498 	int	pk_argc = 0;
499 	char	**pk_argv = NULL;
500 	int	save_errno = 0;
501 
502 	/* Set up for i18n/l10n. */
503 	(void) setlocale(LC_ALL, "");
504 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D. */
505 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
506 #endif
507 	(void) textdomain(TEXT_DOMAIN);
508 
509 	/* Get program base name and move pointer over 0th arg. */
510 	prog = basename(argv[0]);
511 	argv++, argc--;
512 
513 	/* Set up for debug and error output. */
514 	if (argc == 0) {
515 		usage(-1);
516 		return (1);
517 	}
518 
519 	/* Check for help options.  For CLIP-compliance. */
520 	if (strcmp(argv[0], "-?") == 0) {
521 		return (pk_help(argc, argv));
522 	} else if (strcmp(argv[0], "-f") == 0 && argc == 2) {
523 		rv = process_arg_file(argv[1], &pk_argv, &pk_argc);
524 		if (rv)
525 			return (rv);
526 	} else if (argc >= 1 && argv[0][0] == '-') {
527 		usage(-1);
528 		return (1);
529 	}
530 
531 	/* Always turns off Metaslot so that we can see softtoken. */
532 	if (setenv("METASLOT_ENABLED", "false", 1) < 0) {
533 		save_errno = errno;
534 		cryptoerror(LOG_STDERR,
535 		    gettext("Disabling Metaslot failed (%s)."),
536 		    strerror(save_errno));
537 		return (1);
538 	}
539 
540 	/* Begin parsing command line. */
541 	if (pk_argc == 0 && pk_argv == NULL) {
542 		pk_argc = argc;
543 		pk_argv = argv;
544 	}
545 
546 	/* Check for valid verb (or an abbreviation of it). */
547 	found = -1;
548 	for (i = 0; i < num_cmds; i++) {
549 		if (strcmp(cmds[i].verb, pk_argv[0]) == 0) {
550 			if (found < 0) {
551 				found = i;
552 				break;
553 			}
554 		}
555 	}
556 	/* Stop here if no valid verb found. */
557 	if (found < 0) {
558 		cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"),
559 		    pk_argv[0]);
560 		return (1);
561 	}
562 
563 	/* Get to work! */
564 	rv = (*cmds[found].action)(pk_argc, pk_argv);
565 	switch (rv) {
566 	case PK_ERR_NONE:
567 		break;		/* Command succeeded, do nothing. */
568 	case PK_ERR_USAGE:
569 		usage(found);
570 		break;
571 	case PK_ERR_QUIT:
572 		exit(0);
573 		/* NOTREACHED */
574 	case PK_ERR_PK11:
575 	case PK_ERR_SYSTEM:
576 	case PK_ERR_OPENSSL:
577 	case PK_ERR_NSS:
578 	default:
579 		break;
580 	}
581 	return (rv);
582 }
583