pktool.c revision 6051:7b29d160facb
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 2008 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 <libintl.h>
40#include <libgen.h>
41#include <errno.h>
42#include <cryptoutil.h>
43#include <security/cryptoki.h>
44#include "common.h"
45
46/*
47 * The verbcmd construct allows genericizing information about a verb so
48 * that it is easier to manipulate.  Makes parsing code easier to read,
49 * fix, and extend with new verbs.
50 */
51typedef struct verbcmd_s {
52	char	*verb;
53	int	(*action)(int, char *[]);
54	int	mode;
55	char	*summary;
56	char	*synopsis;
57} verbcmd;
58
59/* External declarations for supported verb actions. */
60extern int	pk_setpin(int argc, char *argv[]);
61extern int	pk_list(int argc, char *argv[]);
62extern int	pk_delete(int argc, char *argv[]);
63extern int	pk_import(int argc, char *argv[]);
64extern int	pk_export(int argc, char *argv[]);
65extern int	pk_tokens(int argc, char *argv[]);
66extern int	pk_gencert(int argc, char *argv[]);
67extern int	pk_gencsr(int argc, char *argv[]);
68extern int	pk_download(int argc, char *argv[]);
69extern int	pk_genkey(int argc, char *argv[]);
70extern int	pk_signcsr(int argc, char *argv[]);
71
72/* Forward declarations for "built-in" verb actions. */
73static int	pk_help(int argc, char *argv[]);
74
75#define	TOKEN_IDX 0
76#define	TOKEN_VERB gettext("tokens")
77#define	TOKEN_SUMM gettext("lists all visible PKCS#11 tokens")
78#define	TOKEN_SYN  gettext("tokens")
79
80#define	SETPIN_IDX 1
81#define	SETPIN_VERB gettext("setpin")
82#define	SETPIN_SUMM gettext("changes user authentication passphrase "\
83	"for keystore access")
84#define	SETPIN_SYN gettext(\
85	"setpin [ keystore=pkcs11 ]\n\t\t" \
86	"[ token=token[:manuf[:serial]]]\n\t" \
87	"setpin keystore=nss\n\t\t" \
88	"[ token=token ]\n\t\t" \
89	"[ dir=directory-path ]\n\t\t" \
90	"[ prefix=DBprefix ]\n\t")
91
92#define	LIST_IDX 2
93#define	LIST_VERB gettext("list")
94#define	LIST_SUMM gettext("lists a summary of objects in the keystore")
95#define	LIST_SYN gettext(\
96	"list [ token=token[:manuf[:serial]]]\n\t\t" \
97	"[ objtype=private|public|both ]\n\t\t" \
98	"[ label=label ]\n\t" \
99 \
100	"list objtype=cert[:[public | private | both ]]\n\t\t" \
101	"[ subject=subject-DN ]\n\t\t" \
102	"[ keystore=pkcs11 ]\n\t\t" \
103	"[ issuer=issuer-DN ]\n\t\t" \
104	"[ serial=serial number ]\n\t\t" \
105	"[ label=cert-label ]\n\t\t" \
106	"[ token=token[:manuf[:serial]]]\n\t\t" \
107	"[ criteria=valid|expired|both ]\n\t" \
108 \
109	"list objtype=key[:[public | private | both ]]\n\t\t" \
110	"[ keystore=pkcs11 ]\n\t\t" \
111	"[ subject=subject-DN ]\n\t\t" \
112	"[ label=key-label ]\n\t\t" \
113	"[ token=token[:manuf[:serial]]]\n\t" \
114 \
115	"list keystore=pkcs11 objtype=crl\n\t\t" \
116	"infile=crl-fn\n\t\t" \
117	"[ dir=directory-path ]\n\t" \
118 \
119	"list keystore=nss objtype=cert\n\t\t" \
120	"[ subject=subject-DN ]\n\t\t" \
121	"[ issuer=issuer-DN ]\n\t\t" \
122	"[ serial=serial number ]\n\t\t" \
123	"[ nickname=cert-nickname ]\n\t\t" \
124	"[ token=token[:manuf[:serial]]]\n\t\t" \
125	"[ dir=directory-path ]\n\t\t" \
126	"[ prefix=DBprefix ]\n\t\t" \
127	"[ criteria=valid|expired|both ]\n\t" \
128 \
129	"list keystore=nss objtype=key\n\t\t" \
130	"[ token=token[:manuf[:serial]]]\n\t\t" \
131	"[ dir=directory-path ]\n\t\t" \
132	"[ prefix=DBprefix ]\n\t\t" \
133	"[ nickname=key-nickname ]\n\t" \
134 \
135	"list keystore=file objtype=cert\n\t\t" \
136	"[ subject=subject-DN ]\n\t\t" \
137	"[ issuer=issuer-DN ]\n\t\t" \
138	"[ serial=serial number ]\n\t\t" \
139	"[ infile=cert-fn ]\n\t\t" \
140	"[ dir=directory-path ]\n\t\t" \
141	"[ criteria=valid|expired|both ]\n\t" \
142 \
143	"list keystore=file objtype=key\n\t\t" \
144	"[ infile=key-fn ]\n\t\t" \
145	"[ dir=directory-path ]\n\t" \
146 \
147	"list keystore=file objtype=crl\n\t\t" \
148	"infile=crl-fn\n\t\t" \
149	"[ dir=directory-path ]\n\t")
150
151#define	DELETE_IDX 3
152#define	DELETE_VERB gettext("delete")
153#define	DELETE_SUMM gettext("deletes objects in the keystore")
154#define	DELETE_SYN gettext(\
155	"delete [ token=token[:manuf[:serial]]]\n\t\t" \
156	"[ objtype=private|public|both ]\n\t\t" \
157	"[ label=object-label ]\n\t" \
158 \
159	"delete keystore=nss objtype=cert\n\t\t" \
160	"[ subject=subject-DN ]\n\t\t" \
161	"[ issuer=issuer-DN ]\n\t\t" \
162	"[ serial=serial number ]\n\t\t" \
163	"[ label=cert-label ]\n\t\t" \
164	"[ token=token[:manuf[:serial]]]\n\t\t" \
165	"[ dir=directory-path ]\n\t\t" \
166	"[ prefix=DBprefix ]\n\t\t" \
167	"[ criteria=valid|expired|both ]\n\t" \
168 \
169	"delete keystore=nss objtype=key\n\t\t" \
170	"[ token=token[:manuf[:serial]]]\n\t\t" \
171	"[ dir=directory-path ]\n\t\t" \
172	"[ prefix=DBprefix ]\n\t\t" \
173	"[ nickname=key-nickname ]\n\t\t" \
174 \
175	"delete keystore=nss objtype=crl\n\t\t" \
176	"[ nickname=issuer-nickname ]\n\t\t" \
177	"[ subject=subject-DN ]\n\t\t" \
178	"[ token=token[:manuf[:serial]]]\n\t\t" \
179	"[ dir=directory-path ]\n\t\t" \
180	"[ prefix=DBprefix ]\n\t" \
181 \
182	"delete keystore=pkcs11 " \
183	"objtype=cert[:[public | private | both]]\n\t\t" \
184	"[ subject=subject-DN ]\n\t\t" \
185	"[ issuer=issuer-DN ]\n\t\t" \
186	"[ serial=serial number ]\n\t\t" \
187	"[ label=cert-label ]\n\t\t" \
188	"[ token=token[:manuf[:serial]]]\n\t\t" \
189	"[ criteria=valid|expired|both ]\n\t" \
190 \
191	"delete keystore=pkcs11 " \
192	"objtype=key[:[public | private | both]]\n\t\t" \
193	"[ subject=subject-DN ]\n\t\t" \
194	"[ label=key-label ]\n\t\t" \
195	"[ token=token[:manuf[:serial]]]\n\t" \
196 \
197	"delete keystore=pkcs11 objtype=crl\n\t\t" \
198	"infile=crl-fn\n\t\t" \
199	"[ dir=directory-path ]\n\t" \
200 \
201	"delete keystore=file objtype=cert\n\t\t" \
202	"[ subject=subject-DN ]\n\t\t" \
203	"[ issuer=issuer-DN ]\n\t\t" \
204	"[ serial=serial number ]\n\t\t" \
205	"[ infile=cert-fn ]\n\t\t" \
206	"[ dir=directory-path ]\n\t\t" \
207	"[ criteria=valid|expired|both ]\n\t" \
208 \
209	"delete keystore=file objtype=key\n\t\t" \
210	"[ infile=key-fn ]\n\t\t" \
211	"[ dir=directory-path ]\n\t" \
212 \
213	"delete keystore=file objtype=crl\n\t\t" \
214	"infile=crl-fn\n\t\t" \
215	"[ dir=directory-path ]\n\t")
216
217#define	IMPORT_IDX 4
218#define	IMPORT_VERB gettext("import")
219#define	IMPORT_SUMM gettext("imports objects from an external source")
220#define	IMPORT_SYN gettext(\
221	"import [token=token[:manuf[:serial]]]\n\t\t" \
222	"infile=input-fn\n\t" \
223 \
224	"import keystore=nss objtype=cert\n\t\t" \
225	"infile=input-fn\n\t\t" \
226	"label=cert-label\n\t\t" \
227	"[ trust=trust-value ]\n\t\t" \
228	"[ token=token[:manuf[:serial]]]\n\t\t" \
229	"[ dir=directory-path ]\n\t\t" \
230	"[ prefix=DBprefix ]\n\t" \
231 \
232	"import keystore=nss objtype=crl\n\t\t" \
233	"infile=input-fn\n\t\t" \
234	"[ verifycrl=y|n ]\n\t\t" \
235	"[ token=token[:manuf[:serial]]]\n\t\t" \
236	"[ dir=directory-path ]\n\t\t" \
237	"[ prefix=DBprefix ]\n\t" \
238 \
239	"import keystore=pkcs11\n\t\t" \
240	"infile=input-fn\n\t\t" \
241	"label=label\n\t\t" \
242	"[ objtype=cert|key ]\n\t\t" \
243	"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \
244	"[ sensitive=y|n ]\n\t\t" \
245	"[ extractable=y|n ]\n\t\t" \
246	"[ token=token[:manuf[:serial]]]\n\t" \
247 \
248	"import keystore=pkcs11 objtype=crl\n\t\t" \
249	"infile=input-crl-fn\n\t\t" \
250	"outcrl=output-crl-fn\n\t\t" \
251	"outformat=pem|der\n\t\t" \
252	"[ dir=output-crl-directory-path ]\n\t" \
253 \
254	"import keystore=file\n\t\t" \
255	"infile=input-fn\n\t\t" \
256	"outkey=output-key-fn\n\t\t" \
257	"outcert=output-cert-fn\n\t\t" \
258	"[ dir=output-cert-dir-path ]\n\t\t" \
259	"[ keydir=output-key-dir-path ]\n\t\t" \
260	"[ outformat=pem|der|pkcs12 ]\n\t" \
261 \
262	"import keystore=file objtype=crl\n\t\t" \
263	"infile=input-crl-fn\n\t\t" \
264	"outcrl=output-crl-fn\n\t\t" \
265	"outformat=pem|der\n\t\t" \
266	"[ dir=output-crl-directory-path ]\n\t")
267
268#define	EXPORT_IDX 5
269#define	EXPORT_VERB gettext("export")
270#define	EXPORT_SUMM gettext("exports objects from the keystore to a file")
271#define	EXPORT_SYN gettext(\
272	"export [token=token[:manuf[:serial]]]\n\t\t" \
273	"outfile=output-fn\n\t" \
274 \
275	"export keystore=nss\n\t\t" \
276	"outfile=output-fn\n\t\t" \
277	"[ objtype=cert|key ]\n\t\t" \
278	"[ subject=subject-DN ]\n\t\t" \
279	"[ issuer=issuer-DN ]\n\t\t" \
280	"[ serial=serial number ]\n\t\t" \
281	"[ nickname=cert-nickname ]\n\t\t" \
282	"[ token=token[:manuf[:serial]]]\n\t\t" \
283	"[ dir=directory-path ]\n\t\t" \
284	"[ prefix=DBPrefix ]\n\t\t" \
285	"[ outformat=pem|der|pkcs12 ]\n\t" \
286 \
287	"export keystore=pkcs11\n\t\t" \
288	"outfile=output-fn\n\t\t" \
289	"[ objtype=cert|key ]\n\t\t" \
290	"[ label=label ]\n\t\t" \
291	"[ subject=subject-DN ]\n\t\t" \
292	"[ issuer=issuer-DN ]\n\t\t" \
293	"[ serial=serial number ]\n\t\t" \
294	"[ outformat=pem|der|pkcs12|raw ]\n\t\t" \
295	"[ token=token[:manuf[:serial]]]\n\t" \
296 \
297	"export keystore=file\n\t\t" \
298	"certfile=cert-input-fn\n\t\t" \
299	"keyfile=key-input-fn\n\t\t" \
300	"outfile=output-pkcs12-fn\n\t\t" \
301	"[ dir=directory-path ]\n\t")
302
303#define	GENCERT_IDX 6
304#define	GENCERT_VERB gettext("gencert")
305#define	GENCERT_SUMM gettext("creates a self-signed X.509v3 certificate")
306#define	GENCERT_SYN gettext(\
307	"gencert [-i] keystore=nss\n\t\t" \
308	"label=cert-nickname\n\t\t" \
309	"serial=serial number hex string]\n\t\t" \
310	"subject=subject-DN\n\t\t" \
311	"[ altname=[critical:]SubjectAltName ]\n\t\t" \
312	"[ keyusage=[critical:]usage,usage,...]\n\t\t" \
313	"[ token=token[:manuf[:serial]]]\n\t\t" \
314	"[ dir=directory-path ]\n\t\t" \
315	"[ prefix=DBprefix ]\n\t\t" \
316	"[ keytype=rsa|dsa ]\n\t\t" \
317	"[ keylen=key-size ]\n\t\t" \
318	"[ trust=trust-value ]\n\t\t" \
319	"[ eku=[critical:]EKU name,...]\n\t\t" \
320	"[ lifetime=number-hour|number-day|number-year ]\n\t" \
321 \
322	"gencert [-i] [ keystore=pkcs11 ]\n\t\t" \
323	"label=key/cert-label\n\t\t" \
324	"subject=subject-DN\n\t\t" \
325	"serial=serial number hex string\n\t\t" \
326	"[ altname=[critical:]SubjectAltName ]\n\t\t" \
327	"[ keyusage=[critical:]usage,usage,...]\n\t\t" \
328	"[ token=token[:manuf[:serial]]]\n\t\t" \
329	"[ keytype=rsa|dsa ]\n\t\t" \
330	"[ keylen=key-size ]\n\t\t" \
331	"[ eku=[critical:]EKU name,...]\n\t\t" \
332	"[ lifetime=number-hour|number-day|number-year ]\n\t" \
333 \
334	"gencert [-i] keystore=file\n\t\t" \
335	"outcert=cert_filename\n\t\t" \
336	"outkey=key_filename\n\t\t" \
337	"subject=subject-DN\n\t\t" \
338	"serial=serial number hex string\n\t\t" \
339	"[ altname=[critical:]SubjectAltName ]\n\t\t" \
340	"[ keyusage=[critical:]usage,usage,...]\n\t\t" \
341	"[ format=der|pem ]\n\t\t" \
342	"[ dir=directory-path ]\n\t\t" \
343	"[ prefix=DBprefix ]\n\t\t" \
344	"[ keytype=rsa|dsa ]\n\t\t" \
345	"[ keylen=key-size ]\n\t\t" \
346	"[ eku=[critical:]EKU name,...]\n\t\t" \
347	"[ lifetime=number-hour|number-day|number-year ]\n\t")
348
349#define	GENCSR_IDX 7
350#define	GENCSR_VERB gettext("gencsr")
351#define	GENCSR_SUMM gettext("creates a PKCS#10 certificate signing " \
352	"request file")
353
354#define	GENCSR_SYN gettext(\
355	"gencsr [-i] keystore=nss \n\t\t" \
356	"nickname=cert-nickname\n\t\t" \
357	"outcsr=csr-fn\n\t\t" \
358	"subject=subject-DN\n\t\t" \
359	"[ altname=[critical:]SubjectAltName ]\n\t\t" \
360	"[ keyusage=[critical:]usage,usage,...]\n\t\t" \
361	"[ token=token[:manuf[:serial]]]\n\t\t" \
362	"[ dir=directory-path ]\n\t\t" \
363	"[ prefix=DBprefix ]\n\t\t" \
364	"[ keytype=rsa|dsa ]\n\t\t" \
365	"[ keylen=key-size ]\n\t\t" \
366	"[ eku=[critical:]EKU name,...]\n\t\t" \
367	"[ format=pem|der ]\n\t" \
368 \
369	"gencsr [-i] [ keystore=pkcs11 ]\n\t\t" \
370	"label=key-label\n\t\t" \
371	"outcsr=csr-fn\n\t\t" \
372	"subject=subject-DN\n\t\t" \
373	"[ altname=[critical:]SubjectAltName ]\n\t\t" \
374	"[ keyusage=[critical:]usage,usage,...]\n\t\t" \
375	"[ token=token[:manuf[:serial]]]\n\t\t" \
376	"[ keytype=rsa|dsa ]\n\t\t" \
377	"[ keylen=key-size ]\n\t\t" \
378	"[ eku=[critical:]EKU name,...]\n\t\t" \
379	"[ format=pem|der ]]\n\t" \
380 \
381	"gencsr [-i] keystore=file\n\t\t" \
382	"outcsr=csr-fn\n\t\t" \
383	"outkey=key-fn\n\t\t" \
384	"subject=subject-DN\n\t\t" \
385	"[ altname=[critical:]SubjectAltName ]\n\t\t" \
386	"[ keyusage=[critical:]usage,usage,...]\n\t\t" \
387	"[ keytype=rsa|dsa ]\n\t\t" \
388	"[ keylen=key-size ]\n\t\t" \
389	"[ eku=[critical:]EKU name,...]\n\t\t" \
390	"[ dir=directory-path ]\n\t\t" \
391	"[ format=pem|der ]\n\t")
392
393#define	DOWNLOAD_IDX 8
394#define	DOWNLOAD_VERB gettext("download")
395#define	DOWNLOAD_SUMM gettext("downloads a CRL or certificate file " \
396	"from an external source")
397#define	DOWNLOAD_SYN gettext(\
398	"download url=url_str\n\t\t" \
399	"[ objtype=crl|cert ]\n\t\t" \
400	"[ http_proxy=proxy_str ]\n\t\t" \
401	"[ outfile = outfile ]\n\t")
402
403#define	GENKEY_IDX 9
404#define	GENKEY_VERB gettext("genkey")
405#define	GENKEY_SUMM gettext("creates a symmetric key in the keystore")
406#define	GENKEY_SYN gettext(\
407	"genkey [ keystore=pkcs11 ]\n\t\t" \
408	"label=key-label\n\t\t" \
409	"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \
410	"[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \
411	"[ token=token[:manuf[:serial]]]\n\t\t" \
412	"[ sensitive=y|n ]\n\t\t" \
413	"[ extractable=y|n ]\n\t\t" \
414	"[ print=y|n ]\n\t" \
415 \
416	"genkey keystore=nss\n\t\t" \
417	"label=key-label\n\t\t" \
418	"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \
419	"[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \
420	"[ token=token[:manuf[:serial]]]\n\t\t" \
421	"[ dir=directory-path ]\n\t\t" \
422	"[ prefix=DBprefix ]\n\t" \
423 \
424	"genkey keystore=file\n\t\t" \
425	"outkey=key-fn\n\t\t" \
426	"[ keytype=aes|arcfour|des|3des|generic ]\n\t\t" \
427	"[ keylen=key-size (AES, ARCFOUR or GENERIC only)]\n\t\t" \
428	"[ dir=directory-path ]\n\t\t" \
429	"[ print=y|n ]\n\t")
430
431#define	SIGNCSR_IDX 10
432#define	SIGNCSR_VERB gettext("signcsr")
433#define	SIGNCSR_SUMM gettext("Sign a PKCS#10 Certificate Signing Request")
434#define	SIGNCSR_SYN gettext(\
435	"signcsr keystore=pkcs11\n\t\t" \
436	"signkey=label (label of signing key)\n\t\t" \
437	"csr=CSR filename\n\t\t" \
438	"serial=serial number hex string\n\t\t" \
439	"outcert=filename for final certificate\n\t\t" \
440	"issuer=issuer-DN\n\t\t" \
441	"[ store=y|n ] (store the new cert in NSS DB, default=n)\n\t\t" \
442	"[ outlabel=certificate label ]\n\t\t" \
443	"[ format=pem|der ] (output format)\n\t\t" \
444	"[ subject=subject-DN ] (new subject name)\n\t\t" \
445	"[ altname=subjectAltName ]\n\t\t" \
446	"[ keyusage=[critical:]usage,...]\n\t\t" \
447	"[ eku=[critical:]EKU Name,...]\n\t\t" \
448	"[ lifetime=number-hour|number-day|number-year ]\n\t\t" \
449	"[ token=token[:manuf[:serial]]]\n\t" \
450 \
451	"signcsr keystore=file\n\t\t" \
452	"signkey=filename\n\t\t" \
453	"csr=CSR filename\n\t\t" \
454	"serial=serial number hex string\n\t\t" \
455	"outcert=filename for final certificate\n\t\t" \
456	"issuer=issuer-DN\n\t\t" \
457	"[ format=pem|der ] (output format)\n\t\t" \
458	"[ subject=subject-DN ] (new subject name)\n\t\t" \
459	"[ altname=subjectAltName ]\n\t\t" \
460	"[ keyusage=[critical:]usage,...]\n\t\t" \
461	"[ lifetime=number-hour|number-day|number-year ]\n\t\t" \
462	"[ eku=[critical:]EKU Name,...]\n\t" \
463 \
464	"signcsr keystore=nss\n\t\t" \
465	"signkey=label (label of signing key)\n\t\t" \
466	"csr=CSR filename\n\t\t" \
467	"serial=serial number hex string\n\t\t" \
468	"outcert=filename for final certificate\n\t\t" \
469	"issuer=issuer-DN\n\t\t" \
470	"[ store=y|n ] (store the new cert in NSS DB, default=n)\n\t\t" \
471	"[ outlabel=certificate label ]\n\t\t" \
472	"[ format=pem|der ] (output format)\n\t\t" \
473	"[ subject=subject-DN ] (new subject name)\n\t\t" \
474	"[ altname=subjectAltName ]\n\t\t" \
475	"[ keyusage=[critical:]usage,...]\n\t\t" \
476	"[ eku=[critical:]EKU Name,...]\n\t\t" \
477	"[ lifetime=number-hour|number-day|number-year ]\n\t\t" \
478	"[ token=token[:manuf[:serial]]]\n\t\t" \
479	"[ dir=directory-path ]\n\t\t" \
480	"[ prefix=DBprefix ]\n\t")
481
482#define	HELP_IDX 11
483#define	HELP_VERB gettext("help")
484#define	HELP_SUMM gettext("displays help message")
485#define	HELP_SYN gettext("help\t(help and usage)")
486
487/* Command structure for verbs and their actions.  Do NOT i18n/l10n. */
488static verbcmd	cmds[] = {
489	{ NULL,	pk_tokens, 0, NULL, NULL},
490	{ NULL,	pk_setpin, 0, NULL, NULL},
491	{ NULL, pk_list, 0, NULL, NULL},
492	{ NULL, pk_delete, 0, NULL, NULL},
493	{ NULL,	pk_import, 0, NULL, NULL},
494	{ NULL,	pk_export, 0, NULL, NULL},
495	{ NULL,	pk_gencert, 0, NULL, NULL},
496	{ NULL,	pk_gencsr, 0, NULL, NULL},
497	{ NULL,	pk_download, 0, NULL, NULL},
498	{ NULL,	pk_genkey, 0, NULL, NULL},
499	{ NULL, pk_signcsr, 0, NULL, NULL},
500	{ NULL,	pk_help, 0, NULL, NULL}
501};
502
503static int	num_cmds = sizeof (cmds) / sizeof (verbcmd);
504
505static char	*prog;
506static void	usage(int);
507
508static void
509init_command_list()
510{
511	cmds[TOKEN_IDX].verb = TOKEN_VERB;
512	cmds[TOKEN_IDX].summary = TOKEN_SUMM;
513	cmds[TOKEN_IDX].synopsis = TOKEN_SYN;
514
515	cmds[SETPIN_IDX].verb = SETPIN_VERB;
516	cmds[SETPIN_IDX].summary = SETPIN_SUMM;
517	cmds[SETPIN_IDX].synopsis = SETPIN_SYN;
518
519	cmds[LIST_IDX].verb = LIST_VERB;
520	cmds[LIST_IDX].summary = LIST_SUMM;
521	cmds[LIST_IDX].synopsis = LIST_SYN;
522
523	cmds[DELETE_IDX].verb = DELETE_VERB;
524	cmds[DELETE_IDX].summary = DELETE_SUMM;
525	cmds[DELETE_IDX].synopsis = DELETE_SYN;
526
527	cmds[IMPORT_IDX].verb = IMPORT_VERB;
528	cmds[IMPORT_IDX].summary = IMPORT_SUMM;
529	cmds[IMPORT_IDX].synopsis = IMPORT_SYN;
530
531	cmds[EXPORT_IDX].verb = EXPORT_VERB;
532	cmds[EXPORT_IDX].summary = EXPORT_SUMM;
533	cmds[EXPORT_IDX].synopsis = EXPORT_SYN;
534
535	cmds[GENCERT_IDX].verb = GENCERT_VERB;
536	cmds[GENCERT_IDX].summary = GENCERT_SUMM;
537	cmds[GENCERT_IDX].synopsis = GENCERT_SYN;
538
539	cmds[GENCSR_IDX].verb = GENCSR_VERB;
540	cmds[GENCSR_IDX].summary = GENCSR_SUMM;
541	cmds[GENCSR_IDX].synopsis = GENCSR_SYN;
542
543	cmds[DOWNLOAD_IDX].verb = DOWNLOAD_VERB;
544	cmds[DOWNLOAD_IDX].summary = DOWNLOAD_SUMM;
545	cmds[DOWNLOAD_IDX].synopsis = DOWNLOAD_SYN;
546
547	cmds[GENKEY_IDX].verb = GENKEY_VERB;
548	cmds[GENKEY_IDX].summary = GENKEY_SUMM;
549	cmds[GENKEY_IDX].synopsis = GENKEY_SYN;
550
551	cmds[SIGNCSR_IDX].verb = SIGNCSR_VERB;
552	cmds[SIGNCSR_IDX].summary = SIGNCSR_SUMM;
553	cmds[SIGNCSR_IDX].synopsis = SIGNCSR_SYN;
554
555	cmds[HELP_IDX].verb = HELP_VERB;
556	cmds[HELP_IDX].summary = HELP_SUMM;
557	cmds[HELP_IDX].synopsis = HELP_SYN;
558
559}
560
561/*
562 * Usage information.  This function must be updated when new verbs or
563 * options are added.
564 */
565static void
566usage(int idx)
567{
568	int	i;
569
570	/* Display this block only in command-line mode. */
571	(void) fprintf(stdout, gettext("Usage:\n"));
572	(void) fprintf(stdout, gettext("   %s -?\t(help and usage)\n"),
573	    prog);
574	(void) fprintf(stdout, gettext("   %s -f option_file\n"), prog);
575	(void) fprintf(stdout, gettext("   %s subcommand [options...]\n"),
576	    prog);
577	(void) fprintf(stdout, gettext("where subcommands may be:\n"));
578
579	/* Display only those verbs that match the current tool mode. */
580	if (idx == -1) {
581		for (i = 0; i < num_cmds; i++) {
582			/* Do NOT i18n/l10n. */
583			(void) fprintf(stdout, "   %-8s	- %s\n",
584			    cmds[i].verb, cmds[i].summary);
585		}
586		(void) fprintf(stdout, gettext("\nFurther details on the "
587		    "subcommands can be found by adding \'help\'.\n"
588		    "Ex: pktool gencert help\n\n"));
589	} else {
590		(void) fprintf(stdout, "\t%s\n", cmds[idx].synopsis);
591	}
592}
593
594/*
595 * Provide help, in the form of displaying the usage.
596 */
597static int
598pk_help(int argc, char *argv[])
599/* ARGSUSED */
600{
601	usage(-1);
602	return (0);
603}
604
605/*
606 * Process arguments from the argfile and create a new
607 * argv/argc list to be processed later.
608 */
609static int
610process_arg_file(char *argfile, char ***argv, int *argc)
611{
612	FILE *fp;
613	char argline[2 * BUFSIZ]; /* 2048 bytes should be plenty */
614	char *p;
615	int nargs = 0;
616
617	if ((fp = fopen(argfile, "rF")) == NULL) {
618		(void) fprintf(stderr,
619		    gettext("Cannot read argfile %s: %s\n"),
620		    argfile, strerror(errno));
621		return (errno);
622	}
623
624	while (fgets(argline, sizeof (argline), fp) != NULL) {
625		int j;
626		/* remove trailing whitespace */
627		j = strlen(argline) - 1;
628		while (j >= 0 && isspace(argline[j])) {
629			argline[j] = 0;
630			j--;
631		}
632		/* If it was a blank line, get the next one. */
633		if (!strlen(argline))
634			continue;
635
636		(*argv) = realloc((*argv),
637		    (nargs + 1) * sizeof (char *));
638		if ((*argv) == NULL) {
639			perror("memory error");
640			(void) fclose(fp);
641			return (errno);
642		}
643		p = (char *)strdup(argline);
644		if (p == NULL) {
645			perror("memory error");
646			(void) fclose(fp);
647			return (errno);
648		}
649		(*argv)[nargs] = p;
650		nargs++;
651	}
652	*argc = nargs;
653	(void) fclose(fp);
654	return (0);
655}
656
657/*
658 * MAIN() -- where all the action is
659 */
660int
661main(int argc, char *argv[], char *envp[])
662/* ARGSUSED2 */
663{
664	int	i, found = -1;
665	int	rv;
666	int	pk_argc = 0;
667	char	**pk_argv = NULL;
668	int	save_errno = 0;
669
670	/* Set up for i18n/l10n. */
671	(void) setlocale(LC_ALL, "");
672#if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D. */
673#define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
674#endif
675	(void) textdomain(TEXT_DOMAIN);
676
677	init_command_list();
678
679	/* Get program base name and move pointer over 0th arg. */
680	prog = basename(argv[0]);
681	argv++, argc--;
682
683	/* Set up for debug and error output. */
684	if (argc == 0) {
685		usage(-1);
686		return (1);
687	}
688
689	/* Check for help options.  For CLIP-compliance. */
690	if (strcmp(argv[0], "-?") == 0) {
691		return (pk_help(argc, argv));
692	} else if (strcmp(argv[0], "-f") == 0 && argc == 2) {
693		rv = process_arg_file(argv[1], &pk_argv, &pk_argc);
694		if (rv)
695			return (rv);
696	} else if (argc >= 1 && argv[0][0] == '-') {
697		usage(-1);
698		return (1);
699	}
700
701	/* Always turns off Metaslot so that we can see softtoken. */
702	if (setenv("METASLOT_ENABLED", "false", 1) < 0) {
703		save_errno = errno;
704		cryptoerror(LOG_STDERR,
705		    gettext("Disabling Metaslot failed (%s)."),
706		    strerror(save_errno));
707		return (1);
708	}
709
710	/* Begin parsing command line. */
711	if (pk_argc == 0 && pk_argv == NULL) {
712		pk_argc = argc;
713		pk_argv = argv;
714	}
715
716	/* Check for valid verb (or an abbreviation of it). */
717	found = -1;
718	for (i = 0; i < num_cmds; i++) {
719		if (strcmp(cmds[i].verb, pk_argv[0]) == 0) {
720			if (found < 0) {
721				found = i;
722				break;
723			}
724		}
725	}
726	/* Stop here if no valid verb found. */
727	if (found < 0) {
728		cryptoerror(LOG_STDERR, gettext("Invalid verb: %s"),
729		    pk_argv[0]);
730		return (1);
731	}
732
733	/* Get to work! */
734	rv = (*cmds[found].action)(pk_argc, pk_argv);
735	switch (rv) {
736	case PK_ERR_NONE:
737		break;		/* Command succeeded, do nothing. */
738	case PK_ERR_USAGE:
739		usage(found);
740		break;
741	case PK_ERR_QUIT:
742		exit(0);
743		/* NOTREACHED */
744	case PK_ERR_PK11:
745	case PK_ERR_SYSTEM:
746	case PK_ERR_OPENSSL:
747	case PK_ERR_NSS:
748	default:
749		break;
750	}
751	return (rv);
752}
753