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 contains the functions that are shared among
     28  * the various services this tool will ultimately provide.
     29  * The functions in this file return PKCS#11 CK_RV errors.
     30  * Only one session and one login per token is supported
     31  * at this time.
     32  */
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <ctype.h>
     38 #include <sys/types.h>
     39 #include <sys/stat.h>
     40 #include <fcntl.h>
     41 #include <tzfile.h>
     42 #include <cryptoutil.h>
     43 #include <security/cryptoki.h>
     44 #include <kmfapi.h>
     45 
     46 #include "common.h"
     47 
     48 /* Local status variables. */
     49 static boolean_t	initialized = B_FALSE;
     50 static boolean_t	session_opened = B_FALSE;
     51 static boolean_t	logged_in = B_FALSE;
     52 
     53 /* Supporting structures and global variables for getopt_av(). */
     54 typedef struct	av_opts_s {
     55 	int		shortnm;	/* short name character */
     56 	char		*longnm;	/* long name string, NOT terminated */
     57 	int		longnm_len;	/* length of long name string */
     58 	boolean_t	has_arg;	/* takes optional argument */
     59 } av_opts;
     60 static av_opts		*opts_av = NULL;
     61 static const char	*_save_optstr = NULL;
     62 static int		_save_numopts = 0;
     63 
     64 int			optind_av = 1;
     65 char			*optarg_av = NULL;
     66 
     67 static void close_sess(CK_SESSION_HANDLE);
     68 static void logout_token(CK_SESSION_HANDLE);
     69 
     70 /*
     71  * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
     72  * along with setting/resetting state variables.
     73  */
     74 static CK_RV
     75 init_pkcs11(void)
     76 {
     77 	CK_RV		rv = CKR_OK;
     78 
     79 	/* If C_Initialize() already called, nothing to do here. */
     80 	if (initialized == B_TRUE)
     81 		return (CKR_OK);
     82 
     83 	/* Reset state variables because C_Initialize() not yet done. */
     84 	session_opened = B_FALSE;
     85 	logged_in = B_FALSE;
     86 
     87 	/* Initialize PKCS#11 library. */
     88 	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
     89 	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
     90 		return (rv);
     91 	}
     92 
     93 	initialized = B_TRUE;
     94 	return (CKR_OK);
     95 }
     96 
     97 /*
     98  * Finalize PKCS#11 library and reset state variables.  Open sessions,
     99  * if any, are closed, and thereby any logins are logged out also.
    100  */
    101 void
    102 final_pk11(CK_SESSION_HANDLE sess)
    103 {
    104 
    105 	/* If the library wasn't initialized, nothing to do here. */
    106 	if (!initialized)
    107 		return;
    108 
    109 	/* Make sure the sesion is closed first. */
    110 	close_sess(sess);
    111 
    112 	(void) C_Finalize(NULL);
    113 	initialized = B_FALSE;
    114 }
    115 
    116 /*
    117  * Close PKCS#11 session and reset state variables.  Any logins are
    118  * logged out.
    119  */
    120 static void
    121 close_sess(CK_SESSION_HANDLE sess)
    122 {
    123 
    124 	if (sess == NULL) {
    125 		return;
    126 	}
    127 
    128 	/* If session is already closed, nothing to do here. */
    129 	if (!session_opened)
    130 		return;
    131 
    132 	/* Make sure user is logged out of token. */
    133 	logout_token(sess);
    134 
    135 	(void) C_CloseSession(sess);
    136 	session_opened = B_FALSE;
    137 }
    138 
    139 /*
    140  * Log user out of token and reset status variable.
    141  */
    142 static void
    143 logout_token(CK_SESSION_HANDLE sess)
    144 {
    145 
    146 	if (sess == NULL) {
    147 		return;
    148 	}
    149 
    150 	/* If already logged out, nothing to do here. */
    151 	if (!logged_in)
    152 		return;
    153 
    154 	(void) C_Logout(sess);
    155 	logged_in = B_FALSE;
    156 }
    157 
    158 /*
    159  * Gets PIN from user.  Caller needs to free the returned PIN when done.
    160  * If two prompts are given, the PIN is confirmed with second prompt.
    161  * Note that getphassphrase() may return data in static memory area.
    162  */
    163 CK_RV
    164 get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
    165 {
    166 	char *save_phrase, *phrase1, *phrase2;
    167 
    168 	/* Prompt user for a PIN. */
    169 	if (prompt1 == NULL) {
    170 		return (CKR_ARGUMENTS_BAD);
    171 	}
    172 	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
    173 		return (CKR_FUNCTION_FAILED);
    174 	}
    175 
    176 	/* Duplicate 1st PIN in separate chunk of memory. */
    177 	if ((save_phrase = strdup(phrase1)) == NULL)
    178 		return (CKR_HOST_MEMORY);
    179 
    180 	/* If second prompt given, PIN confirmation is requested. */
    181 	if (prompt2 != NULL) {
    182 		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
    183 			free(save_phrase);
    184 			return (CKR_FUNCTION_FAILED);
    185 		}
    186 		if (strcmp(save_phrase, phrase2) != 0) {
    187 			free(save_phrase);
    188 			return (CKR_PIN_INCORRECT);
    189 		}
    190 	}
    191 
    192 	*pin = (CK_UTF8CHAR_PTR)save_phrase;
    193 	*pinlen = strlen(save_phrase);
    194 	return (CKR_OK);
    195 }
    196 
    197 int
    198 yn_to_int(char *ynstr)
    199 {
    200 	char *y = gettext("yes");
    201 	char *n = gettext("no");
    202 	if (ynstr == NULL)
    203 		return (-1);
    204 
    205 	if (strncasecmp(ynstr, y, 1) == 0)
    206 		return (1);
    207 	else if (strncasecmp(ynstr, n, 1) == 0)
    208 		return (0);
    209 	else
    210 		return (-1);
    211 }
    212 
    213 /*
    214  * Gets yes/no response from user.  If either no prompt is supplied, a
    215  * default prompt is used.  If not message for invalid input is supplied,
    216  * a default will not be provided.  If the user provides no response,
    217  * the input default B_TRUE == yes, B_FALSE == no is returned.
    218  * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
    219  */
    220 boolean_t
    221 yesno(char *prompt, char *invalid, boolean_t dflt)
    222 {
    223 	char	*response, buf[1024];
    224 	int	ans;
    225 
    226 	if (prompt == NULL)
    227 		prompt = gettext("Enter (y)es or (n)o? ");
    228 
    229 	for (;;) {
    230 		/* Prompt user. */
    231 		(void) printf("%s", prompt);
    232 		(void) fflush(stdout);
    233 
    234 		/* Get the response. */
    235 		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
    236 			break;		/* go to default response */
    237 
    238 		/* Skip any leading white space. */
    239 		while (isspace(*response))
    240 			response++;
    241 		if (*response == '\0')
    242 			break;		/* go to default response */
    243 
    244 		ans = yn_to_int(response);
    245 		if (ans == 1)
    246 			return (B_TRUE);
    247 		else if (ans == 0)
    248 			return (B_FALSE);
    249 
    250 		/* Indicate invalid input, and try again. */
    251 		if (invalid != NULL)
    252 			(void) printf("%s", invalid);
    253 	}
    254 	return (dflt);
    255 }
    256 
    257 /*
    258  * Gets the list of slots which have tokens in them.  Keeps adjusting
    259  * the size of the slot list buffer until the call is successful or an
    260  * irrecoverable error occurs.
    261  */
    262 CK_RV
    263 get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
    264 {
    265 	CK_ULONG	tmp_count = 0;
    266 	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
    267 	int		rv = CKR_OK;
    268 
    269 	if (!initialized)
    270 		if ((rv = init_pkcs11()) != CKR_OK)
    271 			return (rv);
    272 
    273 	/*
    274 	 * Get the slot count first because we don't know how many
    275 	 * slots there are and how many of those slots even have tokens.
    276 	 * Don't specify an arbitrary buffer size for the slot list;
    277 	 * it may be too small (see section 11.5 of PKCS#11 spec).
    278 	 * Also select only those slots that have tokens in them,
    279 	 * because this tool has no need to know about empty slots.
    280 	 */
    281 	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
    282 		return (rv);
    283 
    284 	if (tmp_count == 0) {
    285 		*slot_list = NULL_PTR;
    286 		*slot_count = 0;
    287 		return (CKR_OK);
    288 	}
    289 
    290 	/* Allocate initial space for the slot list. */
    291 	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
    292 	    sizeof (CK_SLOT_ID))) == NULL)
    293 		return (CKR_HOST_MEMORY);
    294 
    295 	/* Then get the slot list itself. */
    296 	for (;;) {
    297 		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
    298 			*slot_list = tmp_list;
    299 			*slot_count = tmp_count;
    300 			break;
    301 		}
    302 
    303 		if (rv != CKR_BUFFER_TOO_SMALL) {
    304 			free(tmp_list);
    305 			break;
    306 		}
    307 
    308 		/* If the number of slots grew, try again. */
    309 		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
    310 		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
    311 			free(tmp_list);
    312 			rv = CKR_HOST_MEMORY;
    313 			break;
    314 		}
    315 		tmp_list = tmp2_list;
    316 	}
    317 
    318 	return (rv);
    319 }
    320 
    321 /*
    322  * Breaks out the getopt-style option string into a structure that can be
    323  * traversed later for calls to getopt_av().  Option string is NOT altered,
    324  * but the struct fields point to locations within option string.
    325  */
    326 static int
    327 populate_opts(char *optstring)
    328 {
    329 	int		i;
    330 	av_opts		*temp;
    331 	char		*marker;
    332 
    333 	if (optstring == NULL || *optstring == '\0')
    334 		return (0);
    335 
    336 	/*
    337 	 * This tries to imitate getopt(3c) Each option must conform to:
    338 	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
    339 	 * If long name is missing, the short name is used for long name.
    340 	 */
    341 	for (i = 0; *optstring != '\0'; i++) {
    342 		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
    343 		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
    344 			if (opts_av != NULL)
    345 				free(opts_av);
    346 			opts_av = NULL;
    347 			return (0);
    348 		} else {
    349 			opts_av = (av_opts *)temp;
    350 		}
    351 
    352 		(void) memset(&opts_av[i], 0, sizeof (av_opts));
    353 		marker = optstring;		/* may need optstring later */
    354 
    355 		opts_av[i].shortnm = *marker++;	/* set short name */
    356 
    357 		if (*marker == ':') {		/* check for opt arg */
    358 			marker++;
    359 			opts_av[i].has_arg = B_TRUE;
    360 		}
    361 
    362 		if (*marker == '(') {		/* check and set long name */
    363 			marker++;
    364 			opts_av[i].longnm = marker;
    365 			opts_av[i].longnm_len = strcspn(marker, ")");
    366 			optstring = marker + opts_av[i].longnm_len + 1;
    367 		} else {
    368 			/* use short name option character */
    369 			opts_av[i].longnm = optstring;
    370 			opts_av[i].longnm_len = 1;
    371 			optstring = marker;
    372 		}
    373 	}
    374 
    375 	return (i);
    376 }
    377 
    378 /*
    379  * getopt_av() is very similar to getopt(3c) in that the takes an option
    380  * string, compares command line arguments for matches, and returns a single
    381  * letter option when a match is found.  However, getopt_av() differs from
    382  * getopt(3c) by requiring that only longname options and values be found
    383  * on the command line and all leading dashes are omitted.  In other words,
    384  * it tries to enforce only longname "option=value" arguments on the command
    385  * line.  Boolean options are not allowed either.
    386  */
    387 int
    388 getopt_av(int argc, char * const *argv, const char *optstring)
    389 {
    390 	int	i;
    391 	int	len;
    392 	char   *cur_option;
    393 
    394 	if (optind_av >= argc)
    395 		return (EOF);
    396 
    397 	/* First time or when optstring changes from previous one */
    398 	if (_save_optstr != optstring) {
    399 		if (opts_av != NULL)
    400 			free(opts_av);
    401 		opts_av = NULL;
    402 		_save_optstr = optstring;
    403 		_save_numopts = populate_opts((char *)optstring);
    404 	}
    405 
    406 	for (i = 0; i < _save_numopts; i++) {
    407 		cur_option = argv[optind_av];
    408 
    409 		if (strcmp(cur_option, "--") == 0) {
    410 			optind_av++;
    411 			break;
    412 		}
    413 
    414 		if (cur_option[0] == '-' && strlen(cur_option) == 2) {
    415 			len = 1;
    416 			cur_option++; /* remove "-" */
    417 		} else {
    418 			len = strcspn(cur_option, "=");
    419 		}
    420 
    421 		if (len == opts_av[i].longnm_len && strncmp(cur_option,
    422 		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
    423 			/* matched */
    424 			if (!opts_av[i].has_arg) {
    425 				optind_av++;
    426 				return (opts_av[i].shortnm);
    427 			}
    428 
    429 			/* needs optarg */
    430 			if (cur_option[len] == '=') {
    431 				optarg_av = &(cur_option[len+1]);
    432 				optind_av++;
    433 				return (opts_av[i].shortnm);
    434 			}
    435 
    436 			optarg_av = NULL;
    437 			optind_av++;
    438 			return ((int)'?');
    439 		}
    440 	}
    441 
    442 	return (EOF);
    443 }
    444 
    445 KMF_KEYSTORE_TYPE
    446 KS2Int(char *keystore_str)
    447 {
    448 	if (keystore_str == NULL)
    449 		return (0);
    450 	if (strcasecmp(keystore_str, "pkcs11") == 0)
    451 		return (KMF_KEYSTORE_PK11TOKEN);
    452 	else if (strcasecmp(keystore_str, "nss") == 0)
    453 		return (KMF_KEYSTORE_NSS);
    454 	else if (strcasecmp(keystore_str, "file") == 0)
    455 		return (KMF_KEYSTORE_OPENSSL);
    456 	else
    457 		return (0);
    458 }
    459 
    460 
    461 int
    462 Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg)
    463 {
    464 	if (algm == NULL) {
    465 		*sigAlg = KMF_ALGID_SHA1WithRSA;
    466 		*ktype = KMF_RSA;
    467 	} else if (strcasecmp(algm, "DSA") == 0) {
    468 		*sigAlg = KMF_ALGID_SHA1WithDSA;
    469 		*ktype = KMF_DSA;
    470 	} else if (strcasecmp(algm, "RSA") == 0) {
    471 		*sigAlg = KMF_ALGID_SHA1WithRSA;
    472 		*ktype = KMF_RSA;
    473 	} else {
    474 		return (-1);
    475 	}
    476 	return (0);
    477 }
    478 
    479 int
    480 Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
    481 {
    482 	if (algm == NULL)
    483 		*ktype = KMF_AES;
    484 	else if (strcasecmp(algm, "aes") == 0)
    485 		*ktype = KMF_AES;
    486 	else if (strcasecmp(algm, "arcfour") == 0)
    487 		*ktype = KMF_RC4;
    488 	else if (strcasecmp(algm, "des") == 0)
    489 		*ktype = KMF_DES;
    490 	else if (strcasecmp(algm, "3des") == 0)
    491 		*ktype = KMF_DES3;
    492 	else if (strcasecmp(algm, "generic") == 0)
    493 		*ktype = KMF_GENERIC_SECRET;
    494 	else
    495 		return (-1);
    496 
    497 	return (0);
    498 }
    499 
    500 int
    501 Str2Lifetime(char *ltimestr, uint32_t *ltime)
    502 {
    503 	int num;
    504 	char timetok[6];
    505 
    506 	if (ltimestr == NULL || strlen(ltimestr) == 0) {
    507 		/* default to 1 year lifetime */
    508 		*ltime = SECSPERDAY * DAYSPERNYEAR;
    509 		return (0);
    510 	}
    511 
    512 	(void) memset(timetok, 0, sizeof (timetok));
    513 	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
    514 		return (-1);
    515 
    516 	if (strcasecmp(timetok, "day") == 0||
    517 	    strcasecmp(timetok, "days") == 0) {
    518 		*ltime = num * SECSPERDAY;
    519 	} else if (strcasecmp(timetok, "hour") == 0||
    520 	    strcasecmp(timetok, "hours") == 0) {
    521 		*ltime = num * SECSPERHOUR;
    522 	} else if (strcasecmp(timetok, "year") == 0 ||
    523 	    strcasecmp(timetok, "years") == 0) {
    524 		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
    525 	} else {
    526 		*ltime = 0;
    527 		return (-1);
    528 	}
    529 
    530 	return (0);
    531 }
    532 
    533 int
    534 OT2Int(char *objclass)
    535 {
    536 	char *c = NULL;
    537 	int retval = 0;
    538 
    539 	if (objclass == NULL)
    540 		return (-1);
    541 
    542 	c = strchr(objclass, ':');
    543 	if (c != NULL) {
    544 		if (strcasecmp(c, ":private") == 0)
    545 			retval = PK_PRIVATE_OBJ;
    546 		else if (strcasecmp(c, ":public") == 0)
    547 			retval = PK_PUBLIC_OBJ;
    548 		else if (strcasecmp(c, ":both") == 0)
    549 			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
    550 		else /* unrecognized option */
    551 			return (-1);
    552 
    553 		*c = '\0';
    554 	}
    555 
    556 	if (strcasecmp(objclass, "public") == 0) {
    557 		if (retval)
    558 			return (-1);
    559 		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
    560 	} else if (strcasecmp(objclass, "private") == 0) {
    561 		if (retval)
    562 			return (-1);
    563 		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
    564 	} else if (strcasecmp(objclass, "both") == 0) {
    565 		if (retval)
    566 			return (-1);
    567 		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
    568 	} else if (strcasecmp(objclass, "cert") == 0) {
    569 		return (retval | PK_CERT_OBJ);
    570 	} else if (strcasecmp(objclass, "key") == 0) {
    571 		if (retval == 0) /* return all keys */
    572 			return (retval | PK_KEY_OBJ);
    573 		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
    574 			/* return all keys */
    575 			return (retval | PK_KEY_OBJ);
    576 		else if (retval & PK_PUBLIC_OBJ)
    577 			/* Only return public keys */
    578 			return (retval | PK_PUBKEY_OBJ);
    579 		else if (retval & PK_PRIVATE_OBJ)
    580 			/* Only return private keys */
    581 			return (retval | PK_PRIKEY_OBJ);
    582 	} else if (strcasecmp(objclass, "crl") == 0) {
    583 		if (retval)
    584 			return (-1);
    585 		return (retval | PK_CRL_OBJ);
    586 	}
    587 
    588 	if (retval == 0) /* No matches found */
    589 		retval = -1;
    590 	return (retval);
    591 }
    592 
    593 KMF_ENCODE_FORMAT
    594 Str2Format(char *formstr)
    595 {
    596 	if (formstr == NULL || strcasecmp(formstr, "der") == 0)
    597 		return (KMF_FORMAT_ASN1);
    598 	if (strcasecmp(formstr, "pem") == 0)
    599 		return (KMF_FORMAT_PEM);
    600 	if (strcasecmp(formstr, "pkcs12") == 0)
    601 		return (KMF_FORMAT_PKCS12);
    602 	if (strcasecmp(formstr, "raw") == 0)
    603 		return (KMF_FORMAT_RAWKEY);
    604 
    605 	return (KMF_FORMAT_UNDEF);
    606 }
    607 
    608 KMF_RETURN
    609 select_token(void *kmfhandle, char *token, int readonly)
    610 {
    611 	KMF_ATTRIBUTE attlist[10];
    612 	int i = 0;
    613 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
    614 	KMF_RETURN rv = KMF_OK;
    615 
    616 	if (token == NULL)
    617 		return (KMF_ERR_BAD_PARAMETER);
    618 
    619 	kmf_set_attr_at_index(attlist, i,
    620 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
    621 	    sizeof (kstype));
    622 	i++;
    623 
    624 	if (token) {
    625 		kmf_set_attr_at_index(attlist, i,
    626 		    KMF_TOKEN_LABEL_ATTR, token,
    627 		    strlen(token));
    628 		i++;
    629 	}
    630 
    631 	kmf_set_attr_at_index(attlist, i,
    632 	    KMF_READONLY_ATTR, &readonly,
    633 	    sizeof (readonly));
    634 	i++;
    635 
    636 	rv = kmf_configure_keystore(kmfhandle, i, attlist);
    637 	if (rv == KMF_ERR_TOKEN_SELECTED)
    638 		rv = KMF_OK;
    639 	return (rv);
    640 }
    641 
    642 KMF_RETURN
    643 configure_nss(void *kmfhandle, char *dir, char *prefix)
    644 {
    645 	KMF_ATTRIBUTE attlist[10];
    646 	int i = 0;
    647 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
    648 	KMF_RETURN rv = KMF_OK;
    649 
    650 	kmf_set_attr_at_index(attlist, i,
    651 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
    652 	    sizeof (kstype));
    653 	i++;
    654 
    655 	if (dir) {
    656 		kmf_set_attr_at_index(attlist, i,
    657 		    KMF_DIRPATH_ATTR, dir,
    658 		    strlen(dir));
    659 		i++;
    660 	}
    661 
    662 	if (prefix) {
    663 		kmf_set_attr_at_index(attlist, i,
    664 		    KMF_CERTPREFIX_ATTR, prefix,
    665 		    strlen(prefix));
    666 		i++;
    667 
    668 		kmf_set_attr_at_index(attlist, i,
    669 		    KMF_KEYPREFIX_ATTR, prefix,
    670 		    strlen(prefix));
    671 		i++;
    672 	}
    673 
    674 	rv = kmf_configure_keystore(kmfhandle, i, attlist);
    675 	if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
    676 		rv = KMF_OK;
    677 
    678 	return (rv);
    679 }
    680 
    681 KMF_RETURN
    682 get_pk12_password(KMF_CREDENTIAL *cred)
    683 {
    684 	KMF_RETURN rv = KMF_OK;
    685 	char prompt[1024];
    686 
    687 	/*
    688 	 * Get the password to use for the PK12 encryption.
    689 	 */
    690 	(void) strlcpy(prompt,
    691 	    gettext("Enter password to use for "
    692 	    "accessing the PKCS12 file: "), sizeof (prompt));
    693 
    694 	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
    695 	    (ulong_t *)&cred->credlen) != CKR_OK) {
    696 		cred->cred = NULL;
    697 		cred->credlen = 0;
    698 	}
    699 
    700 	return (rv);
    701 }
    702 
    703 #define	FILENAME_PROMPT gettext("Filename:")
    704 #define	FILENAME_MINLEN	1
    705 #define	FILENAME_MAXLEN MAXPATHLEN
    706 
    707 #define	COUNTRY_PROMPT	gettext("Country Name (2 letter code) [US]:")
    708 #define	STATE_PROMPT	gettext("State or Province Name (full name) " \
    709 	"[Some-State]:")
    710 #define	LOCALITY_PROMPT	gettext("Locality Name (eg, city) []:")
    711 #define	ORG_PROMPT	gettext("Organization Name (eg, company) []:")
    712 #define	UNIT_PROMPT	gettext("Organizational Unit Name (eg, section) []:")
    713 #define	NAME_PROMPT	gettext("Common Name (eg, YOUR name) []:")
    714 #define	EMAIL_PROMPT	gettext("Email Address []:")
    715 
    716 #define	SERNO_PROMPT	gettext("Serial Number (hex value, example: " \
    717 	"0x01020304):")
    718 #define	SERNO_MINLEN	3
    719 #define	SERNO_MAXLEN	42
    720 
    721 #define	LABEL_PROMPT	gettext("Enter a label for the certificate:")
    722 #define	LABEL_MINLEN	1
    723 #define	LABEL_MAXLEN	1024
    724 
    725 #define	COUNTRY_DEFAULT "US"
    726 #define	STATE_DEFAULT	NULL
    727 #define	INVALID_INPUT 	gettext("Invalid input; please re-enter ...")
    728 
    729 #define	SUBNAMESIZ	1024
    730 #define	RDN_MIN		1
    731 #define	RDN_MAX		64
    732 #define	COUNTRYNAME_MIN	2
    733 #define	COUNTRYNAME_MAX	2
    734 
    735 static char *
    736 get_input_string(char *prompt, char *default_str, int min_len, int max_len)
    737 {
    738 	char buf[1024];
    739 	char *response = NULL;
    740 	char *ret = NULL;
    741 	int len;
    742 
    743 	for (;;) {
    744 		(void) printf("\t%s", prompt);
    745 		(void) fflush(stdout);
    746 
    747 		response = fgets(buf, sizeof (buf), stdin);
    748 		if (response == NULL) {
    749 			if (default_str != NULL) {
    750 				ret = strdup(default_str);
    751 			}
    752 			break;
    753 		}
    754 
    755 		/* Skip any leading white space. */
    756 		while (isspace(*response))
    757 			response++;
    758 		if (*response == '\0') {
    759 			if (default_str != NULL) {
    760 				ret = strdup(default_str);
    761 			}
    762 			break;
    763 		}
    764 
    765 		len = strlen(response);
    766 		response[len-1] = '\0'; /* get rid of "LF" */
    767 		len--;
    768 		if (len >= min_len && len <= max_len) {
    769 			ret = strdup(response);
    770 			break;
    771 		}
    772 
    773 		(void) printf("%s\n", INVALID_INPUT);
    774 
    775 	}
    776 
    777 	return (ret);
    778 }
    779 
    780 int
    781 get_filename(char *txt, char **result)
    782 {
    783 	char prompt[1024];
    784 	char *fname = NULL;
    785 
    786 	(void) snprintf(prompt, sizeof (prompt),
    787 	    gettext("Enter filename for the %s: "),
    788 	    txt);
    789 	fname = get_input_string(prompt, NULL,
    790 	    FILENAME_MINLEN, FILENAME_MAXLEN);
    791 	*result = fname;
    792 	return (0);
    793 }
    794 
    795 int
    796 get_certlabel(char **result)
    797 {
    798 	char *label = NULL;
    799 
    800 	label = get_input_string(LABEL_PROMPT, NULL,
    801 	    LABEL_MINLEN, LABEL_MAXLEN);
    802 	*result = label;
    803 	return (0);
    804 }
    805 
    806 int
    807 get_serial(char **result)
    808 {
    809 	char *serial = NULL;
    810 
    811 	serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN,
    812 	    SERNO_MAXLEN);
    813 
    814 	*result = serial;
    815 	return (0);
    816 }
    817 
    818 int
    819 get_subname(char **result)
    820 {
    821 	char *country = NULL;
    822 	char *state = NULL;
    823 	char *locality = NULL;
    824 	char *org = NULL;
    825 	char *unit = NULL;
    826 	char *name = NULL;
    827 	char *email = NULL;
    828 	char *subname = NULL;
    829 
    830 	(void) printf("Entering following fields for subject (a DN) ...\n");
    831 	country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
    832 	    COUNTRYNAME_MIN, COUNTRYNAME_MAX);
    833 	if (country == NULL)
    834 		return (-1);
    835 
    836 	state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
    837 	    RDN_MIN, RDN_MAX);
    838 
    839 	locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
    840 	org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
    841 	unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
    842 	name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
    843 	email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
    844 
    845 	/* Now create a subject name from the input strings */
    846 	if ((subname = malloc(SUBNAMESIZ)) == NULL)
    847 		goto out;
    848 
    849 	(void) memset(subname, 0, SUBNAMESIZ);
    850 	(void) strlcpy(subname, "C=", SUBNAMESIZ);
    851 	(void) strlcat(subname, country, SUBNAMESIZ);
    852 	if (state != NULL) {
    853 		(void) strlcat(subname, ", ST=", SUBNAMESIZ);
    854 		(void) strlcat(subname, state, SUBNAMESIZ);
    855 	}
    856 
    857 	if (locality != NULL) {
    858 		(void) strlcat(subname, ", L=", SUBNAMESIZ);
    859 		(void) strlcat(subname, locality, SUBNAMESIZ);
    860 	}
    861 
    862 	if (org != NULL) {
    863 		(void) strlcat(subname, ", O=", SUBNAMESIZ);
    864 		(void) strlcat(subname, org, SUBNAMESIZ);
    865 	}
    866 
    867 	if (unit != NULL) {
    868 		(void) strlcat(subname, ", OU=", SUBNAMESIZ);
    869 		(void) strlcat(subname, unit, SUBNAMESIZ);
    870 	}
    871 
    872 	if (name != NULL) {
    873 		(void) strlcat(subname, ", CN=", SUBNAMESIZ);
    874 		(void) strlcat(subname, name, SUBNAMESIZ);
    875 	}
    876 
    877 	if (email != NULL) {
    878 		(void) strlcat(subname, ", E=", SUBNAMESIZ);
    879 		(void) strlcat(subname, email, SUBNAMESIZ);
    880 	}
    881 
    882 out:
    883 	if (country)
    884 		free(country);
    885 	if (state)
    886 		free(state);
    887 	if (locality)
    888 		free(locality);
    889 	if (org)
    890 		free(org);
    891 	if (unit)
    892 		free(unit);
    893 	if (name)
    894 		free(name);
    895 	if (email)
    896 		free(email);
    897 
    898 	if (subname == NULL)
    899 		return (-1);
    900 	else {
    901 		*result = subname;
    902 		return (0);
    903 	}
    904 }
    905 
    906 /*
    907  * Parse a string of KeyUsage values and convert
    908  * them to the correct KU Bits.
    909  * The field may be marked "critical" by prepending
    910  * "critical:" to the list.
    911  * EX:  critical:digitialSignature,keyEncipherment
    912  */
    913 KMF_RETURN
    914 verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
    915 {
    916 	KMF_RETURN ret = KMF_OK;
    917 	uint16_t kuval;
    918 	char *k;
    919 
    920 	*kubits = 0;
    921 	if (kustr == NULL || strlen(kustr) == 0)
    922 		return (KMF_ERR_BAD_PARAMETER);
    923 
    924 	/* Check to see if this is critical */
    925 	if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) {
    926 		*critical = TRUE;
    927 		kustr += strlen("critical:");
    928 	} else {
    929 		*critical = FALSE;
    930 	}
    931 
    932 	k = strtok(kustr, ",");
    933 	while (k != NULL) {
    934 		kuval = kmf_string_to_ku(k);
    935 		if (kuval == 0) {
    936 			*kubits = 0;
    937 			return (KMF_ERR_BAD_PARAMETER);
    938 		}
    939 		*kubits |= kuval;
    940 		k = strtok(NULL, ",");
    941 	}
    942 
    943 	return (ret);
    944 }
    945 
    946 /*
    947  * Verify the alternate subject label is real or invalid.
    948  *
    949  * The field may be marked "critical" by prepending
    950  * "critical:" to the list.
    951  * EX:  "critical:IP=1.2.3.4"
    952  */
    953 KMF_RETURN
    954 verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
    955 {
    956 	char *p;
    957 	KMF_RETURN rv = KMF_OK;
    958 
    959 	/* Check to see if this is critical */
    960 	if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) {
    961 		*critical = TRUE;
    962 		arg += strlen("critical:");
    963 	} else {
    964 		*critical = FALSE;
    965 	}
    966 
    967 	/* Make sure there is an "=" sign */
    968 	p = strchr(arg, '=');
    969 	if (p == NULL)
    970 		return (KMF_ERR_BAD_PARAMETER);
    971 
    972 	p[0] = '\0';
    973 
    974 	if (strcmp(arg, "IP") == 0)
    975 		*type = GENNAME_IPADDRESS;
    976 	else if (strcmp(arg, "DNS") == 0)
    977 		*type = GENNAME_DNSNAME;
    978 	else if (strcmp(arg, "EMAIL") == 0)
    979 		*type = GENNAME_RFC822NAME;
    980 	else if (strcmp(arg, "URI") == 0)
    981 		*type = GENNAME_URI;
    982 	else if (strcmp(arg, "DN") == 0)
    983 		*type = GENNAME_DIRECTORYNAME;
    984 	else if (strcmp(arg, "RID") == 0)
    985 		*type = GENNAME_REGISTEREDID;
    986 	else if (strcmp(arg, "KRB") == 0)
    987 		*type = GENNAME_KRB5PRINC;
    988 	else if (strcmp(arg, "UPN") == 0)
    989 		*type = GENNAME_SCLOGON_UPN;
    990 	else
    991 		rv = KMF_ERR_BAD_PARAMETER;
    992 
    993 	p[0] = '=';
    994 
    995 	return (rv);
    996 }
    997 
    998 int
    999 get_token_password(KMF_KEYSTORE_TYPE kstype,
   1000 	char *token_spec, KMF_CREDENTIAL *cred)
   1001 {
   1002 	char	prompt[1024];
   1003 	char	temptoken[32];
   1004 	char	*p = NULL;
   1005 	char	*t = NULL;
   1006 	int	len;
   1007 
   1008 	(void) memset(temptoken, 0, sizeof (temptoken));
   1009 	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
   1010 		p = strchr(token_spec, ':');
   1011 		if (p != NULL)
   1012 			*p = 0;
   1013 	}
   1014 	len = strlen(token_spec);
   1015 	if (len > sizeof (temptoken))
   1016 		len = sizeof (temptoken);
   1017 
   1018 	(void) strncpy(temptoken, token_spec, len);
   1019 
   1020 	/*
   1021 	 * Strip trailing whitespace
   1022 	 */
   1023 	t = temptoken + (len - 1);
   1024 	while (isspace(*t) && t >= temptoken) {
   1025 		*t = 0x00;
   1026 		t--;
   1027 	}
   1028 
   1029 	/*
   1030 	 * Login to the token first.
   1031 	 */
   1032 	(void) snprintf(prompt, sizeof (prompt),
   1033 	    gettext(DEFAULT_TOKEN_PROMPT), temptoken);
   1034 
   1035 	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
   1036 	    (ulong_t *)&cred->credlen) != CKR_OK) {
   1037 		cred->cred = NULL;
   1038 		cred->credlen = 0;
   1039 	}
   1040 
   1041 	if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
   1042 		*p = ':';
   1043 	return (KMF_OK);
   1044 }
   1045 
   1046 KMF_RETURN
   1047 verify_file(char *filename)
   1048 {
   1049 	KMF_RETURN ret = KMF_OK;
   1050 	int fd;
   1051 
   1052 	/*
   1053 	 * Attempt to open with  the EXCL flag so that if
   1054 	 * it already exists, the open will fail.  It will
   1055 	 * also fail if the file cannot be created due to
   1056 	 * permissions on the parent directory, or if the
   1057 	 * parent directory itself does not exist.
   1058 	 */
   1059 	fd = open(filename, O_CREAT | O_EXCL, 0600);
   1060 	if (fd == -1)
   1061 		return (KMF_ERR_OPEN_FILE);
   1062 
   1063 	/* If we were able to create it, delete it. */
   1064 	(void) close(fd);
   1065 	(void) unlink(filename);
   1066 
   1067 	return (ret);
   1068 }
   1069 
   1070 void
   1071 display_error(void *handle, KMF_RETURN errcode, char *prefix)
   1072 {
   1073 	KMF_RETURN rv1, rv2;
   1074 	char *plugin_errmsg = NULL;
   1075 	char *kmf_errmsg = NULL;
   1076 
   1077 	rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg);
   1078 	rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg);
   1079 
   1080 	cryptoerror(LOG_STDERR, "%s:", prefix);
   1081 	if (rv1 == KMF_OK && plugin_errmsg) {
   1082 		cryptoerror(LOG_STDERR, gettext("keystore error: %s"),
   1083 		    plugin_errmsg);
   1084 		kmf_free_str(plugin_errmsg);
   1085 	}
   1086 
   1087 	if (rv2 == KMF_OK && kmf_errmsg) {
   1088 		cryptoerror(LOG_STDERR, gettext("libkmf error: %s"),
   1089 		    kmf_errmsg);
   1090 		kmf_free_str(kmf_errmsg);
   1091 	}
   1092 
   1093 	if (rv1 != KMF_OK && rv2 != KMF_OK)
   1094 		cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
   1095 
   1096 }
   1097 
   1098 static KMF_RETURN
   1099 addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid)
   1100 {
   1101 	if (newoid != NULL && ekus != NULL) {
   1102 		ekus->eku_count++;
   1103 
   1104 		ekus->critlist = realloc(ekus->critlist,
   1105 		    ekus->eku_count * sizeof (int));
   1106 		if (ekus->critlist != NULL)
   1107 			ekus->critlist[ekus->eku_count-1] = critical;
   1108 		else
   1109 			return (KMF_ERR_MEMORY);
   1110 
   1111 		ekus->ekulist = realloc(
   1112 		    ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
   1113 		if (ekus->ekulist != NULL)
   1114 			ekus->ekulist[ekus->eku_count-1] = *newoid;
   1115 		else
   1116 			return (KMF_ERR_MEMORY);
   1117 	}
   1118 	return (KMF_OK);
   1119 }
   1120 
   1121 void
   1122 free_eku_list(EKU_LIST *ekus)
   1123 {
   1124 	if (ekus != NULL && ekus->eku_count > 0) {
   1125 		int i;
   1126 		for (i = 0; i < ekus->eku_count; i++) {
   1127 			kmf_free_data(&ekus->ekulist[i]);
   1128 		}
   1129 		free(ekus->ekulist);
   1130 		free(ekus->critlist);
   1131 		free(ekus);
   1132 	}
   1133 }
   1134 
   1135 static KMF_RETURN
   1136 parse_ekus(char *ekustr, EKU_LIST *ekus)
   1137 {
   1138 	KMF_RETURN rv = KMF_OK;
   1139 	KMF_OID *newoid;
   1140 	int critical;
   1141 
   1142 	if (strncasecmp(ekustr, "critical:",
   1143 	    strlen("critical:")) == 0) {
   1144 		critical = TRUE;
   1145 		ekustr += strlen("critical:");
   1146 	} else {
   1147 		critical = FALSE;
   1148 	}
   1149 	newoid = kmf_ekuname_to_oid(ekustr);
   1150 	if (newoid != NULL) {
   1151 		rv = addToEKUList(ekus, critical, newoid);
   1152 		free(newoid);
   1153 	} else {
   1154 		rv = PK_ERR_USAGE;
   1155 	}
   1156 
   1157 	return (rv);
   1158 }
   1159 
   1160 KMF_RETURN
   1161 verify_ekunames(char *ekuliststr, EKU_LIST **ekulist)
   1162 {
   1163 	KMF_RETURN rv = KMF_OK;
   1164 	char *p;
   1165 	EKU_LIST *ekus = NULL;
   1166 
   1167 	if (ekuliststr == NULL || strlen(ekuliststr) == 0)
   1168 		return (0);
   1169 
   1170 	ekus = calloc(sizeof (EKU_LIST), 1);
   1171 	if (ekus == NULL)
   1172 		return (KMF_ERR_MEMORY);
   1173 
   1174 	/*
   1175 	 * The list should be comma separated list of EKU Names.
   1176 	 */
   1177 	p = strtok(ekuliststr, ",");
   1178 
   1179 	/* If no tokens found, then maybe it's just a single EKU value */
   1180 	if (p == NULL) {
   1181 		rv = parse_ekus(ekuliststr, ekus);
   1182 	}
   1183 
   1184 	while (p != NULL) {
   1185 		rv = parse_ekus(p, ekus);
   1186 
   1187 		if (rv != KMF_OK)
   1188 			break;
   1189 		p = strtok(NULL, ",");
   1190 	}
   1191 
   1192 	if (rv != KMF_OK)
   1193 		free_eku_list(ekus);
   1194 	else
   1195 		*ekulist = ekus;
   1196 
   1197 	return (rv);
   1198 }
   1199 
   1200 KMF_RETURN
   1201 token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth)
   1202 {
   1203 	CK_TOKEN_INFO info;
   1204 	CK_SLOT_ID slot;
   1205 	CK_RV ckrv;
   1206 	KMF_RETURN rv;
   1207 
   1208 	*auth = 0;
   1209 	rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot);
   1210 	if (rv != KMF_OK)
   1211 		return (rv);
   1212 
   1213 	ckrv = C_GetTokenInfo(slot, &info);
   1214 	if (ckrv != KMF_OK)
   1215 		return (KMF_ERR_INTERNAL);
   1216 
   1217 	*auth = (info.flags & CKF_LOGIN_REQUIRED);
   1218 
   1219 	return (KMF_OK);
   1220 }
   1221