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