xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/common.c (revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*99ebb4caSwyllys  * Common Development and Distribution License (the "License").
6*99ebb4caSwyllys  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*99ebb4caSwyllys  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This file contains the functions that are shared among
307c478bd9Sstevel@tonic-gate  * the various services this tool will ultimately provide.
317711facfSdinak  * The functions in this file return PKCS#11 CK_RV errors.
327711facfSdinak  * Only one session and one login per token is supported
337711facfSdinak  * at this time.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <ctype.h>
40*99ebb4caSwyllys #include <sys/types.h>
41*99ebb4caSwyllys #include <sys/stat.h>
42*99ebb4caSwyllys #include <fcntl.h>
43*99ebb4caSwyllys #include <tzfile.h>
447c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
457c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
46*99ebb4caSwyllys #include <kmfapi.h>
477c478bd9Sstevel@tonic-gate 
48*99ebb4caSwyllys #include "common.h"
497711facfSdinak 
507711facfSdinak /* Local status variables. */
517711facfSdinak static boolean_t	initialized = B_FALSE;
527711facfSdinak static boolean_t	session_opened = B_FALSE;
537711facfSdinak static boolean_t	logged_in = B_FALSE;
547c478bd9Sstevel@tonic-gate 
5549e21299Sdinak /* Supporting structures and global variables for getopt_av(). */
5649e21299Sdinak typedef struct	av_opts_s {
5749e21299Sdinak 	int		shortnm;	/* short name character */
5849e21299Sdinak 	char		*longnm;	/* long name string, NOT terminated */
5949e21299Sdinak 	int		longnm_len;	/* length of long name string */
6049e21299Sdinak 	boolean_t	has_arg;	/* takes optional argument */
6149e21299Sdinak } av_opts;
6249e21299Sdinak static av_opts		*opts_av = NULL;
6349e21299Sdinak static const char	*_save_optstr = NULL;
6449e21299Sdinak static int		_save_numopts = 0;
6549e21299Sdinak 
6649e21299Sdinak int			optind_av = 1;
6749e21299Sdinak char			*optarg_av = NULL;
6849e21299Sdinak 
69*99ebb4caSwyllys static void close_sess(CK_SESSION_HANDLE);
70*99ebb4caSwyllys static void logout_token(CK_SESSION_HANDLE);
71*99ebb4caSwyllys 
727c478bd9Sstevel@tonic-gate /*
737711facfSdinak  * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
747711facfSdinak  * along with setting/resetting state variables.
757c478bd9Sstevel@tonic-gate  */
767711facfSdinak CK_RV
777711facfSdinak init_pk11(void)
787c478bd9Sstevel@tonic-gate {
797711facfSdinak 	CK_RV		rv = CKR_OK;
807711facfSdinak 
817711facfSdinak 	/* If C_Initialize() already called, nothing to do here. */
827711facfSdinak 	if (initialized == B_TRUE)
837711facfSdinak 		return (CKR_OK);
847c478bd9Sstevel@tonic-gate 
857711facfSdinak 	/* Reset state variables because C_Initialize() not yet done. */
867711facfSdinak 	session_opened = B_FALSE;
877711facfSdinak 	logged_in = B_FALSE;
887c478bd9Sstevel@tonic-gate 
897711facfSdinak 	/* Initialize PKCS#11 library. */
907711facfSdinak 	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
917711facfSdinak 	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
927711facfSdinak 		return (rv);
937711facfSdinak 	}
947c478bd9Sstevel@tonic-gate 
957711facfSdinak 	initialized = B_TRUE;
967711facfSdinak 	return (CKR_OK);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007711facfSdinak  * Finalize PKCS#11 library and reset state variables.  Open sessions,
1017711facfSdinak  * if any, are closed, and thereby any logins are logged out also.
1027c478bd9Sstevel@tonic-gate  */
1037711facfSdinak void
1047711facfSdinak final_pk11(CK_SESSION_HANDLE sess)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate 
1077711facfSdinak 	/* If the library wasn't initialized, nothing to do here. */
1087711facfSdinak 	if (!initialized)
1097711facfSdinak 		return;
1107c478bd9Sstevel@tonic-gate 
1117711facfSdinak 	/* Make sure the sesion is closed first. */
1127711facfSdinak 	close_sess(sess);
1137711facfSdinak 
1147711facfSdinak 	(void) C_Finalize(NULL);
1157711facfSdinak 	initialized = B_FALSE;
1167711facfSdinak }
1177711facfSdinak 
1187711facfSdinak /*
1197711facfSdinak  * Close PKCS#11 session and reset state variables.  Any logins are
1207711facfSdinak  * logged out.
1217711facfSdinak  */
122*99ebb4caSwyllys static void
1237711facfSdinak close_sess(CK_SESSION_HANDLE sess)
1247711facfSdinak {
1257711facfSdinak 
1267711facfSdinak 	if (sess == NULL) {
1277711facfSdinak 		return;
1287711facfSdinak 	}
1297711facfSdinak 
1307711facfSdinak 	/* If session is already closed, nothing to do here. */
1317711facfSdinak 	if (!session_opened)
1327711facfSdinak 		return;
1337711facfSdinak 
1347711facfSdinak 	/* Make sure user is logged out of token. */
1357711facfSdinak 	logout_token(sess);
1367711facfSdinak 
1377711facfSdinak 	(void) C_CloseSession(sess);
1387711facfSdinak 	session_opened = B_FALSE;
1397711facfSdinak }
1407711facfSdinak 
1417711facfSdinak /*
1427711facfSdinak  * Log user out of token and reset status variable.
1437711facfSdinak  */
144*99ebb4caSwyllys static void
1457711facfSdinak logout_token(CK_SESSION_HANDLE sess)
1467711facfSdinak {
1477711facfSdinak 
1487711facfSdinak 	if (sess == NULL) {
1497711facfSdinak 		return;
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate 
1527711facfSdinak 	/* If already logged out, nothing to do here. */
1537711facfSdinak 	if (!logged_in)
1547711facfSdinak 		return;
1557711facfSdinak 
1567711facfSdinak 	(void) C_Logout(sess);
1577711facfSdinak 	logged_in = B_FALSE;
1587711facfSdinak }
1597711facfSdinak 
1607711facfSdinak /*
1617711facfSdinak  * Gets PIN from user.  Caller needs to free the returned PIN when done.
1627711facfSdinak  * If two prompts are given, the PIN is confirmed with second prompt.
1637711facfSdinak  * Note that getphassphrase() may return data in static memory area.
1647711facfSdinak  */
1657711facfSdinak CK_RV
1667711facfSdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
1677711facfSdinak {
1687711facfSdinak 	char		*save_phrase, *phrase1, *phrase2;
1697711facfSdinak 
170*99ebb4caSwyllys 
171*99ebb4caSwyllys #ifdef DEBUG
172*99ebb4caSwyllys 	if (getenv("TOKENPIN") != NULL) {
173*99ebb4caSwyllys 		*pin = (CK_UTF8CHAR_PTR)strdup(getenv("TOKENPIN"));
174*99ebb4caSwyllys 		*pinlen = strlen((char *)(*pin));
175*99ebb4caSwyllys 		return (CKR_OK);
176*99ebb4caSwyllys 	}
177*99ebb4caSwyllys #endif /* DEBUG */
1787711facfSdinak 
1797711facfSdinak 	/* Prompt user for a PIN. */
1807711facfSdinak 	if (prompt1 == NULL) {
1817711facfSdinak 		return (CKR_ARGUMENTS_BAD);
1827711facfSdinak 	}
1837711facfSdinak 	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
1847711facfSdinak 		return (CKR_FUNCTION_FAILED);
1857711facfSdinak 	}
1867711facfSdinak 
1877711facfSdinak 	/* Duplicate 1st PIN in separate chunk of memory. */
1887711facfSdinak 	if ((save_phrase = strdup(phrase1)) == NULL)
1897711facfSdinak 		return (CKR_HOST_MEMORY);
1907711facfSdinak 
1917711facfSdinak 	/* If second prompt given, PIN confirmation is requested. */
1927711facfSdinak 	if (prompt2 != NULL) {
1937711facfSdinak 		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
1947711facfSdinak 			free(save_phrase);
1957711facfSdinak 			return (CKR_FUNCTION_FAILED);
1967711facfSdinak 		}
1977711facfSdinak 		if (strcmp(save_phrase, phrase2) != 0) {
1987711facfSdinak 			free(save_phrase);
1997711facfSdinak 			return (CKR_PIN_INCORRECT);
2007711facfSdinak 		}
2017711facfSdinak 	}
2027711facfSdinak 
2037711facfSdinak 	*pin = (CK_UTF8CHAR_PTR)save_phrase;
2047711facfSdinak 	*pinlen = strlen(save_phrase);
2057711facfSdinak 	return (CKR_OK);
2067711facfSdinak }
2077711facfSdinak 
2087711facfSdinak /*
2097711facfSdinak  * Gets yes/no response from user.  If either no prompt is supplied, a
2107711facfSdinak  * default prompt is used.  If not message for invalid input is supplied,
2117711facfSdinak  * a default will not be provided.  If the user provides no response,
2127711facfSdinak  * the input default B_TRUE == yes, B_FALSE == no is returned.
2137711facfSdinak  * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
2147711facfSdinak  */
2157711facfSdinak boolean_t
2167711facfSdinak yesno(char *prompt, char *invalid, boolean_t dflt)
2177711facfSdinak {
2187711facfSdinak 	char		*response, buf[1024];
2197711facfSdinak 	char		*yes = gettext("yes");
2207711facfSdinak 	char		*no = gettext("no");
2217711facfSdinak 
222*99ebb4caSwyllys 
223*99ebb4caSwyllys #ifdef DEBUG
224*99ebb4caSwyllys 	/* If debugging or testing, return TRUE and avoid prompting */
225*99ebb4caSwyllys 	if (getenv("TOKENPIN") != NULL) {
226*99ebb4caSwyllys 		return (B_TRUE);
227*99ebb4caSwyllys 	}
228*99ebb4caSwyllys #endif /* DEBUG */
2297711facfSdinak 
2307711facfSdinak 	if (prompt == NULL)
2317711facfSdinak 		prompt = gettext("Enter (y)es or (n)o? ");
2327711facfSdinak 
2337711facfSdinak 	for (;;) {
2347711facfSdinak 		/* Prompt user. */
2357711facfSdinak 		(void) printf("%s", prompt);
2367711facfSdinak 		(void) fflush(stdout);
2377711facfSdinak 
2387711facfSdinak 		/* Get the response. */
2397711facfSdinak 		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
2407711facfSdinak 			break;		/* go to default response */
2417711facfSdinak 
2427711facfSdinak 		/* Skip any leading white space. */
2437711facfSdinak 		while (isspace(*response))
2447711facfSdinak 			response++;
2457711facfSdinak 		if (*response == '\0')
2467711facfSdinak 			break;		/* go to default response */
2477711facfSdinak 
2487711facfSdinak 		/* Is it valid input?  Return appropriately. */
2497711facfSdinak 		if (strncasecmp(response, yes, 1) == 0)
2507711facfSdinak 			return (B_TRUE);
2517711facfSdinak 		if (strncasecmp(response, no, 1) == 0)
2527711facfSdinak 			return (B_FALSE);
2537711facfSdinak 
2547711facfSdinak 		/* Indicate invalid input, and try again. */
2557711facfSdinak 		if (invalid != NULL)
2567711facfSdinak 		    (void) printf("%s", invalid);
2577711facfSdinak 	}
2587711facfSdinak 	return (dflt);
2597711facfSdinak }
2607711facfSdinak 
2617711facfSdinak /*
2627711facfSdinak  * Gets the list of slots which have tokens in them.  Keeps adjusting
2637711facfSdinak  * the size of the slot list buffer until the call is successful or an
2647711facfSdinak  * irrecoverable error occurs.
2657711facfSdinak  */
2667711facfSdinak CK_RV
2677711facfSdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
2687711facfSdinak {
2697711facfSdinak 	CK_ULONG	tmp_count = 0;
2707711facfSdinak 	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
2717711facfSdinak 	int		rv = CKR_OK;
2727711facfSdinak 
2737711facfSdinak 	if (!initialized)
2747711facfSdinak 		if ((rv = init_pk11()) != CKR_OK)
2757711facfSdinak 			return (rv);
2767711facfSdinak 
2777711facfSdinak 	/*
2787711facfSdinak 	 * Get the slot count first because we don't know how many
2797711facfSdinak 	 * slots there are and how many of those slots even have tokens.
2807711facfSdinak 	 * Don't specify an arbitrary buffer size for the slot list;
2817711facfSdinak 	 * it may be too small (see section 11.5 of PKCS#11 spec).
2827711facfSdinak 	 * Also select only those slots that have tokens in them,
2837711facfSdinak 	 * because this tool has no need to know about empty slots.
2847711facfSdinak 	 */
2857711facfSdinak 	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
2867711facfSdinak 		return (rv);
2877711facfSdinak 
2887711facfSdinak 	if (tmp_count == 0) {
2897711facfSdinak 		*slot_list = NULL_PTR;
2907711facfSdinak 		*slot_count = 0;
2917711facfSdinak 		return (CKR_OK);
2927711facfSdinak 	}
2937711facfSdinak 
2947711facfSdinak 	/* Allocate initial space for the slot list. */
2957711facfSdinak 	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
2967711facfSdinak 	    sizeof (CK_SLOT_ID))) == NULL)
2977711facfSdinak 		return (CKR_HOST_MEMORY);
2987711facfSdinak 
2997711facfSdinak 	/* Then get the slot list itself. */
3007711facfSdinak 	for (;;) {
3017711facfSdinak 		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
3027711facfSdinak 			*slot_list = tmp_list;
3037711facfSdinak 			*slot_count = tmp_count;
3047711facfSdinak 			break;
3057711facfSdinak 		}
3067711facfSdinak 
3077711facfSdinak 		if (rv != CKR_BUFFER_TOO_SMALL) {
3087711facfSdinak 			free(tmp_list);
3097711facfSdinak 			break;
3107711facfSdinak 		}
3117711facfSdinak 
3127711facfSdinak 		/* If the number of slots grew, try again. */
3137711facfSdinak 		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
3147711facfSdinak 		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
3157711facfSdinak 			free(tmp_list);
3167711facfSdinak 			rv = CKR_HOST_MEMORY;
3177711facfSdinak 			break;
3187711facfSdinak 		}
3197711facfSdinak 		tmp_list = tmp2_list;
3207711facfSdinak 	}
3217711facfSdinak 
3227711facfSdinak 	return (rv);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
326*99ebb4caSwyllys  * Breaks out the getopt-style option string into a structure that can be
327*99ebb4caSwyllys  * traversed later for calls to getopt_av().  Option string is NOT altered,
328*99ebb4caSwyllys  * but the struct fields point to locations within option string.
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate static int
331*99ebb4caSwyllys populate_opts(char *optstring)
3327c478bd9Sstevel@tonic-gate {
333*99ebb4caSwyllys 	int		i;
334*99ebb4caSwyllys 	av_opts		*temp;
3357c478bd9Sstevel@tonic-gate 	char		*marker;
3367c478bd9Sstevel@tonic-gate 
337*99ebb4caSwyllys 	if (optstring == NULL || *optstring == '\0')
338*99ebb4caSwyllys 		return (0);
339*99ebb4caSwyllys 
340*99ebb4caSwyllys 	/*
341*99ebb4caSwyllys 	 * This tries to imitate getopt(3c) Each option must conform to:
342*99ebb4caSwyllys 	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
343*99ebb4caSwyllys 	 * If long name is missing, the short name is used for long name.
344*99ebb4caSwyllys 	 */
345*99ebb4caSwyllys 	for (i = 0; *optstring != '\0'; i++) {
346*99ebb4caSwyllys 		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
347*99ebb4caSwyllys 		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
348*99ebb4caSwyllys 			if (opts_av != NULL)
349*99ebb4caSwyllys 				free(opts_av);
350*99ebb4caSwyllys 			opts_av = NULL;
351*99ebb4caSwyllys 			return (0);
352*99ebb4caSwyllys 		} else {
353*99ebb4caSwyllys 			opts_av = (av_opts *)temp;
354*99ebb4caSwyllys 		}
3557c478bd9Sstevel@tonic-gate 
356*99ebb4caSwyllys 		(void) memset(&opts_av[i], 0, sizeof (av_opts));
357*99ebb4caSwyllys 		marker = optstring;		/* may need optstring later */
3587c478bd9Sstevel@tonic-gate 
359*99ebb4caSwyllys 		opts_av[i].shortnm = *marker++;	/* set short name */
360*99ebb4caSwyllys 
361*99ebb4caSwyllys 		if (*marker == ':') {		/* check for opt arg */
362*99ebb4caSwyllys 			marker++;
363*99ebb4caSwyllys 			opts_av[i].has_arg = B_TRUE;
364*99ebb4caSwyllys 		}
365*99ebb4caSwyllys 
366*99ebb4caSwyllys 		if (*marker == '(') {		/* check and set long name */
367*99ebb4caSwyllys 			marker++;
368*99ebb4caSwyllys 			opts_av[i].longnm = marker;
369*99ebb4caSwyllys 			opts_av[i].longnm_len = strcspn(marker, ")");
370*99ebb4caSwyllys 			optstring = marker + opts_av[i].longnm_len + 1;
371*99ebb4caSwyllys 		} else {
372*99ebb4caSwyllys 			/* use short name option character */
373*99ebb4caSwyllys 			opts_av[i].longnm = optstring;
374*99ebb4caSwyllys 			opts_av[i].longnm_len = 1;
375*99ebb4caSwyllys 			optstring = marker;
376*99ebb4caSwyllys 		}
377*99ebb4caSwyllys 	}
378*99ebb4caSwyllys 
379*99ebb4caSwyllys 	return (i);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate /*
383*99ebb4caSwyllys  * getopt_av() is very similar to getopt(3c) in that the takes an option
384*99ebb4caSwyllys  * string, compares command line arguments for matches, and returns a single
385*99ebb4caSwyllys  * letter option when a match is found.  However, getopt_av() differs from
386*99ebb4caSwyllys  * getopt(3c) by requiring that only longname options and values be found
387*99ebb4caSwyllys  * on the command line and all leading dashes are omitted.  In other words,
388*99ebb4caSwyllys  * it tries to enforce only longname "option=value" arguments on the command
389*99ebb4caSwyllys  * line.  Boolean options are not allowed either.
3907c478bd9Sstevel@tonic-gate  */
391*99ebb4caSwyllys int
392*99ebb4caSwyllys getopt_av(int argc, char * const *argv, const char *optstring)
3937c478bd9Sstevel@tonic-gate {
394*99ebb4caSwyllys 	int	i;
395*99ebb4caSwyllys 	int	len;
396*99ebb4caSwyllys 	char   *cur_option;
3977c478bd9Sstevel@tonic-gate 
398*99ebb4caSwyllys 	if (optind_av >= argc)
399*99ebb4caSwyllys 		return (EOF);
4007c478bd9Sstevel@tonic-gate 
401*99ebb4caSwyllys 	/* First time or when optstring changes from previous one */
402*99ebb4caSwyllys 	if (_save_optstr != optstring) {
403*99ebb4caSwyllys 		if (opts_av != NULL)
404*99ebb4caSwyllys 		    free(opts_av);
405*99ebb4caSwyllys 		opts_av = NULL;
406*99ebb4caSwyllys 		_save_optstr = optstring;
407*99ebb4caSwyllys 		_save_numopts = populate_opts((char *)optstring);
408*99ebb4caSwyllys 	}
4097c478bd9Sstevel@tonic-gate 
410*99ebb4caSwyllys 	for (i = 0; i < _save_numopts; i++) {
411*99ebb4caSwyllys 		cur_option = argv[optind_av];
4127c478bd9Sstevel@tonic-gate 
413*99ebb4caSwyllys 		if (strcmp(cur_option, "--") == 0) {
414*99ebb4caSwyllys 			optind_av++;
415*99ebb4caSwyllys 			break;
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 
418*99ebb4caSwyllys 		if (cur_option[0] == '-' && strlen(cur_option) == 2) {
419*99ebb4caSwyllys 			len = 1;
420*99ebb4caSwyllys 			cur_option++; /* remove "-" */
421*99ebb4caSwyllys 		} else {
422*99ebb4caSwyllys 			len = strcspn(cur_option, "=");
423*99ebb4caSwyllys 		}
4247c478bd9Sstevel@tonic-gate 
425*99ebb4caSwyllys 		if (len == opts_av[i].longnm_len && strncmp(cur_option,
426*99ebb4caSwyllys 		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
427*99ebb4caSwyllys 			/* matched */
428*99ebb4caSwyllys 			if (!opts_av[i].has_arg) {
429*99ebb4caSwyllys 				optind_av++;
430*99ebb4caSwyllys 				return (opts_av[i].shortnm);
431*99ebb4caSwyllys 			}
432*99ebb4caSwyllys 
433*99ebb4caSwyllys 			/* needs optarg */
434*99ebb4caSwyllys 			if (cur_option[len] == '=') {
435*99ebb4caSwyllys 				optarg_av = &(cur_option[len+1]);
436*99ebb4caSwyllys 				optind_av++;
437*99ebb4caSwyllys 				return (opts_av[i].shortnm);
438*99ebb4caSwyllys 			}
439*99ebb4caSwyllys 
440*99ebb4caSwyllys 			optarg_av = NULL;
441*99ebb4caSwyllys 			optind_av++;
442*99ebb4caSwyllys 			return ((int)'?');
443*99ebb4caSwyllys 		}
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 
446*99ebb4caSwyllys 	return (EOF);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
449*99ebb4caSwyllys KMF_KEYSTORE_TYPE
450*99ebb4caSwyllys KS2Int(char *keystore_str)
45149e21299Sdinak {
452*99ebb4caSwyllys 	if (keystore_str == NULL)
453*99ebb4caSwyllys 		return (0);
454*99ebb4caSwyllys 	if (!strcasecmp(keystore_str, "pkcs11"))
455*99ebb4caSwyllys 		return (KMF_KEYSTORE_PK11TOKEN);
456*99ebb4caSwyllys 	else if (!strcasecmp(keystore_str, "nss"))
457*99ebb4caSwyllys 		return (KMF_KEYSTORE_NSS);
458*99ebb4caSwyllys 	else if (!strcasecmp(keystore_str, "file"))
459*99ebb4caSwyllys 		return (KMF_KEYSTORE_OPENSSL);
460*99ebb4caSwyllys 	else
461*99ebb4caSwyllys 		return (0);
462*99ebb4caSwyllys }
46349e21299Sdinak 
46449e21299Sdinak 
465*99ebb4caSwyllys int
466*99ebb4caSwyllys Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg)
467*99ebb4caSwyllys {
468*99ebb4caSwyllys 	if (algm == NULL) {
469*99ebb4caSwyllys 		*sigAlg = KMF_ALGID_MD5WithRSA;
470*99ebb4caSwyllys 		*ktype = KMF_RSA;
471*99ebb4caSwyllys 	} else if (strcasecmp(algm, "DSA") == 0) {
472*99ebb4caSwyllys 		*sigAlg = KMF_ALGID_SHA1WithDSA;
473*99ebb4caSwyllys 		*ktype = KMF_DSA;
474*99ebb4caSwyllys 	} else if (strcasecmp(algm, "RSA") == 0) {
475*99ebb4caSwyllys 		*sigAlg = KMF_ALGID_MD5WithRSA;
476*99ebb4caSwyllys 		*ktype = KMF_RSA;
477*99ebb4caSwyllys 	} else {
478*99ebb4caSwyllys 		return (-1);
47949e21299Sdinak 	}
480*99ebb4caSwyllys 	return (0);
48149e21299Sdinak }
48249e21299Sdinak 
483*99ebb4caSwyllys int
484*99ebb4caSwyllys Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
48549e21299Sdinak {
486*99ebb4caSwyllys 	if (algm == NULL)
487*99ebb4caSwyllys 		*ktype = KMF_AES;
488*99ebb4caSwyllys 	else if (strcasecmp(algm, "aes") == 0)
489*99ebb4caSwyllys 		*ktype = KMF_AES;
490*99ebb4caSwyllys 	else if (strcasecmp(algm, "arcfour") == 0)
491*99ebb4caSwyllys 		*ktype = KMF_RC4;
492*99ebb4caSwyllys 	else if (strcasecmp(algm, "des") == 0)
493*99ebb4caSwyllys 		*ktype = KMF_DES;
494*99ebb4caSwyllys 	else if (strcasecmp(algm, "3des") == 0)
495*99ebb4caSwyllys 		*ktype = KMF_DES3;
496*99ebb4caSwyllys 	else
497*99ebb4caSwyllys 		return (-1);
49849e21299Sdinak 
499*99ebb4caSwyllys 	return (0);
50049e21299Sdinak }
50149e21299Sdinak 
50249e21299Sdinak int
503*99ebb4caSwyllys Str2Lifetime(char *ltimestr, uint32_t *ltime)
50449e21299Sdinak {
505*99ebb4caSwyllys 	int num;
506*99ebb4caSwyllys 	char timetok[6];
50749e21299Sdinak 
508*99ebb4caSwyllys 	if (ltimestr == NULL || !strlen(ltimestr)) {
509*99ebb4caSwyllys 		/* default to 1 year lifetime */
510*99ebb4caSwyllys 		*ltime = SECSPERDAY * DAYSPERNYEAR;
511*99ebb4caSwyllys 		return (0);
51249e21299Sdinak 	}
51349e21299Sdinak 
514*99ebb4caSwyllys 	(void) memset(timetok, 0, sizeof (timetok));
515*99ebb4caSwyllys 	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
516*99ebb4caSwyllys 		return (-1);
51749e21299Sdinak 
518*99ebb4caSwyllys 	if (!strcasecmp(timetok, "day") ||
519*99ebb4caSwyllys 	    !strcasecmp(timetok, "days")) {
520*99ebb4caSwyllys 		*ltime = num * SECSPERDAY;
521*99ebb4caSwyllys 	} else if (!strcasecmp(timetok, "hour") ||
522*99ebb4caSwyllys 		!strcasecmp(timetok, "hours")) {
523*99ebb4caSwyllys 		*ltime = num * SECSPERHOUR;
524*99ebb4caSwyllys 	} else if (!strcasecmp(timetok, "year") ||
525*99ebb4caSwyllys 		!strcasecmp(timetok, "years")) {
526*99ebb4caSwyllys 		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
527*99ebb4caSwyllys 	} else {
528*99ebb4caSwyllys 		*ltime = 0;
52949e21299Sdinak 		return (-1);
53049e21299Sdinak 	}
53149e21299Sdinak 
532*99ebb4caSwyllys 	return (0);
533*99ebb4caSwyllys }
53449e21299Sdinak 
535*99ebb4caSwyllys int
536*99ebb4caSwyllys OT2Int(char *objclass)
537*99ebb4caSwyllys {
538*99ebb4caSwyllys 	char *c = NULL;
539*99ebb4caSwyllys 	int retval = 0;
54049e21299Sdinak 
541*99ebb4caSwyllys 	if (objclass == NULL)
542*99ebb4caSwyllys 		return (-1);
54349e21299Sdinak 
544*99ebb4caSwyllys 	c = strchr(objclass, ':');
545*99ebb4caSwyllys 	if (c != NULL) {
546*99ebb4caSwyllys 		if (!strcasecmp(c, ":private"))
547*99ebb4caSwyllys 			retval = PK_PRIVATE_OBJ;
548*99ebb4caSwyllys 		else if (!strcasecmp(c, ":public"))
549*99ebb4caSwyllys 			retval = PK_PUBLIC_OBJ;
550*99ebb4caSwyllys 		else if (!strcasecmp(c, ":both"))
551*99ebb4caSwyllys 			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
552*99ebb4caSwyllys 		else /* unrecognized option */
553*99ebb4caSwyllys 			return (-1);
554*99ebb4caSwyllys 
555*99ebb4caSwyllys 		*c = '\0';
556*99ebb4caSwyllys 	}
557*99ebb4caSwyllys 
558*99ebb4caSwyllys 	if (!strcasecmp(objclass, "public")) {
559*99ebb4caSwyllys 		if (retval)
560*99ebb4caSwyllys 			return (-1);
561*99ebb4caSwyllys 		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ |
562*99ebb4caSwyllys 			PK_PUBKEY_OBJ);
563*99ebb4caSwyllys 	} else if (!strcasecmp(objclass, "private")) {
564*99ebb4caSwyllys 		if (retval)
565*99ebb4caSwyllys 			return (-1);
566*99ebb4caSwyllys 		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
567*99ebb4caSwyllys 	} else if (!strcasecmp(objclass, "both")) {
568*99ebb4caSwyllys 		if (retval)
569*99ebb4caSwyllys 			return (-1);
570*99ebb4caSwyllys 		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
571*99ebb4caSwyllys 	} else if (!strcasecmp(objclass, "cert")) {
572*99ebb4caSwyllys 		return (retval | PK_CERT_OBJ);
573*99ebb4caSwyllys 	} else if (!strcasecmp(objclass, "key")) {
574*99ebb4caSwyllys 		if (retval == 0) /* return all keys */
575*99ebb4caSwyllys 			return (retval | PK_KEY_OBJ);
576*99ebb4caSwyllys 		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
577*99ebb4caSwyllys 			/* return all keys */
578*99ebb4caSwyllys 			return (retval | PK_KEY_OBJ);
579*99ebb4caSwyllys 		else if (retval & PK_PUBLIC_OBJ)
580*99ebb4caSwyllys 			/* Only return public keys */
581*99ebb4caSwyllys 			return (retval | PK_PUBKEY_OBJ);
582*99ebb4caSwyllys 		else if (retval & PK_PRIVATE_OBJ)
583*99ebb4caSwyllys 			/* Only return private keys */
584*99ebb4caSwyllys 			return (retval | PK_PRIKEY_OBJ);
585*99ebb4caSwyllys 	} else if (!strcasecmp(objclass, "crl")) {
586*99ebb4caSwyllys 		if (retval)
587*99ebb4caSwyllys 			return (-1);
588*99ebb4caSwyllys 		return (retval | PK_CRL_OBJ);
589*99ebb4caSwyllys 	}
590*99ebb4caSwyllys 
591*99ebb4caSwyllys 	if (retval == 0) /* No matches found */
592*99ebb4caSwyllys 		retval = -1;
593*99ebb4caSwyllys 	return (retval);
59449e21299Sdinak }
59549e21299Sdinak 
596*99ebb4caSwyllys KMF_ENCODE_FORMAT
597*99ebb4caSwyllys Str2Format(char *formstr)
5987c478bd9Sstevel@tonic-gate {
599*99ebb4caSwyllys 	if (formstr == NULL || !strcasecmp(formstr, "der"))
600*99ebb4caSwyllys 		return (KMF_FORMAT_ASN1);
601*99ebb4caSwyllys 	if (!strcasecmp(formstr, "pem"))
602*99ebb4caSwyllys 		return (KMF_FORMAT_PEM);
603*99ebb4caSwyllys 	if (!strcasecmp(formstr, "pkcs12"))
604*99ebb4caSwyllys 		return (KMF_FORMAT_PKCS12);
605*99ebb4caSwyllys 
606*99ebb4caSwyllys 	return (KMF_FORMAT_UNDEF);
607*99ebb4caSwyllys }
6087c478bd9Sstevel@tonic-gate 
6097711facfSdinak 
610*99ebb4caSwyllys KMF_RETURN
611*99ebb4caSwyllys select_token(void *kmfhandle, char *token,
612*99ebb4caSwyllys 	int readonly)
613*99ebb4caSwyllys {
614*99ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
615*99ebb4caSwyllys 	KMF_CONFIG_PARAMS  config;
6167711facfSdinak 
617*99ebb4caSwyllys 	if (token == NULL)
618*99ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
6197c478bd9Sstevel@tonic-gate 
620*99ebb4caSwyllys 	(void) memset(&config, 0, sizeof (config));
621*99ebb4caSwyllys 	config.kstype = KMF_KEYSTORE_PK11TOKEN;
622*99ebb4caSwyllys 	config.pkcs11config.label = token;
623*99ebb4caSwyllys 	config.pkcs11config.readonly = readonly;
6247711facfSdinak 
625*99ebb4caSwyllys 	rv = KMF_ConfigureKeystore(kmfhandle, &config);
626*99ebb4caSwyllys 	if (rv == KMF_ERR_TOKEN_SELECTED)
627*99ebb4caSwyllys 		rv = KMF_OK;
628*99ebb4caSwyllys 	return (rv);
6297711facfSdinak }
6307711facfSdinak 
631*99ebb4caSwyllys 
632*99ebb4caSwyllys KMF_RETURN
633*99ebb4caSwyllys configure_nss(void *kmfhandle, char *dir, char *prefix)
6347711facfSdinak {
635*99ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
636*99ebb4caSwyllys 	KMF_CONFIG_PARAMS  config;
6377711facfSdinak 
638*99ebb4caSwyllys 	(void) memset(&config, 0, sizeof (config));
639*99ebb4caSwyllys 	config.kstype = KMF_KEYSTORE_NSS;
640*99ebb4caSwyllys 	config.nssconfig.configdir = dir;
641*99ebb4caSwyllys 	config.nssconfig.certPrefix = prefix;
642*99ebb4caSwyllys 	config.nssconfig.keyPrefix = prefix;
643*99ebb4caSwyllys 	config.nssconfig.secModName = NULL;
6447711facfSdinak 
645*99ebb4caSwyllys 	rv = KMF_ConfigureKeystore(kmfhandle, &config);
646*99ebb4caSwyllys 	if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
647*99ebb4caSwyllys 		rv = KMF_OK;
6487c478bd9Sstevel@tonic-gate 
649*99ebb4caSwyllys 	return (rv);
650*99ebb4caSwyllys }
6517711facfSdinak 
652*99ebb4caSwyllys 
653*99ebb4caSwyllys KMF_RETURN
654*99ebb4caSwyllys get_pk12_password(KMF_CREDENTIAL *cred)
655*99ebb4caSwyllys {
656*99ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
657*99ebb4caSwyllys 	char prompt[1024];
6587711facfSdinak 
6597711facfSdinak 	/*
660*99ebb4caSwyllys 	 * Get the password to use for the PK12 encryption.
6617711facfSdinak 	 */
662*99ebb4caSwyllys 	(void) strlcpy(prompt,
663*99ebb4caSwyllys 		gettext("Enter password to use for "
664*99ebb4caSwyllys 			"accessing the PKCS12 file: "),
665*99ebb4caSwyllys 		sizeof (prompt));
6667711facfSdinak 
667*99ebb4caSwyllys 	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
668*99ebb4caSwyllys 		(ulong_t *)&cred->credlen) != CKR_OK) {
669*99ebb4caSwyllys 		cred->cred = NULL;
670*99ebb4caSwyllys 		cred->credlen = 0;
6717711facfSdinak 	}
6727711facfSdinak 
6737711facfSdinak 	return (rv);
6747711facfSdinak }
6757711facfSdinak 
6767711facfSdinak 
677*99ebb4caSwyllys #define	COUNTRY_PROMPT	"Country Name (2 letter code) [US]:"
678*99ebb4caSwyllys #define	STATE_PROMPT	"State or Province Name (full name) [Some-State]:"
679*99ebb4caSwyllys #define	LOCALITY_PROMPT	"Locality Name (eg, city) []:"
680*99ebb4caSwyllys #define	ORG_PROMPT	"Organization Name (eg, company) []:"
681*99ebb4caSwyllys #define	UNIT_PROMPT	"Organizational Unit Name (eg, section) []:"
682*99ebb4caSwyllys #define	NAME_PROMPT	"Common Name (eg, YOUR name) []:"
683*99ebb4caSwyllys #define	EMAIL_PROMPT	"Email Address []:"
6847711facfSdinak 
685*99ebb4caSwyllys #define	COUNTRY_DEFAULT "US"
686*99ebb4caSwyllys #define	STATE_DEFAULT	"Some-State"
687*99ebb4caSwyllys #define	INVALID_INPUT 	"Invalid input; please re-enter ..."
6887711facfSdinak 
689*99ebb4caSwyllys #define	SUBNAMESIZ	1024
690*99ebb4caSwyllys #define	RDN_MIN		1
691*99ebb4caSwyllys #define	RDN_MAX		64
692*99ebb4caSwyllys #define	COUNTRYNAME_MIN	2
693*99ebb4caSwyllys #define	COUNTRYNAME_MAX	2
6947711facfSdinak 
695*99ebb4caSwyllys static char *
696*99ebb4caSwyllys get_input_string(char *prompt, char *default_str, int min_len, int max_len)
697*99ebb4caSwyllys {
698*99ebb4caSwyllys 	char buf[1024];
699*99ebb4caSwyllys 	char *response = NULL;
700*99ebb4caSwyllys 	char *ret = NULL;
701*99ebb4caSwyllys 	int len;
7027711facfSdinak 
703*99ebb4caSwyllys 	for (;;) {
704*99ebb4caSwyllys 		(void) printf("\t%s", prompt);
705*99ebb4caSwyllys 		(void) fflush(stdout);
706*99ebb4caSwyllys 
707*99ebb4caSwyllys 		response = fgets(buf, sizeof (buf), stdin);
708*99ebb4caSwyllys 		if (response == NULL) {
709*99ebb4caSwyllys 			if (default_str != NULL) {
710*99ebb4caSwyllys 				ret = strdup(default_str);
711*99ebb4caSwyllys 			}
712*99ebb4caSwyllys 			break;
713*99ebb4caSwyllys 		}
714*99ebb4caSwyllys 
715*99ebb4caSwyllys 		/* Skip any leading white space. */
716*99ebb4caSwyllys 		while (isspace(*response))
717*99ebb4caSwyllys 			response++;
718*99ebb4caSwyllys 		if (*response == '\0') {
719*99ebb4caSwyllys 			if (default_str != NULL) {
720*99ebb4caSwyllys 				ret = strdup(default_str);
721*99ebb4caSwyllys 			}
722*99ebb4caSwyllys 			break;
723*99ebb4caSwyllys 		}
724*99ebb4caSwyllys 
725*99ebb4caSwyllys 		len = strlen(response);
726*99ebb4caSwyllys 		response[len-1] = '\0'; /* get rid of "LF" */
727*99ebb4caSwyllys 		len--;
728*99ebb4caSwyllys 		if (len >= min_len && len <= max_len) {
729*99ebb4caSwyllys 			ret = strdup(response);
730*99ebb4caSwyllys 			break;
7317711facfSdinak 		}
7327711facfSdinak 
733*99ebb4caSwyllys 		(void) printf("%s\n", INVALID_INPUT);
734*99ebb4caSwyllys 
7357711facfSdinak 	}
7367711facfSdinak 
737*99ebb4caSwyllys 	return (ret);
738*99ebb4caSwyllys }
7397711facfSdinak 
740*99ebb4caSwyllys int
741*99ebb4caSwyllys get_subname(char **result)
742*99ebb4caSwyllys {
743*99ebb4caSwyllys 	char *country = NULL;
744*99ebb4caSwyllys 	char *state = NULL;
745*99ebb4caSwyllys 	char *locality = NULL;
746*99ebb4caSwyllys 	char *org = NULL;
747*99ebb4caSwyllys 	char *unit = NULL;
748*99ebb4caSwyllys 	char *name = NULL;
749*99ebb4caSwyllys 	char *email = NULL;
750*99ebb4caSwyllys 	char *subname = NULL;
751*99ebb4caSwyllys 
752*99ebb4caSwyllys 	(void) printf("Entering following fields for subject (a DN) ...\n");
753*99ebb4caSwyllys 	country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
754*99ebb4caSwyllys 	    COUNTRYNAME_MIN, COUNTRYNAME_MAX);
755*99ebb4caSwyllys 	if (country == NULL)
756*99ebb4caSwyllys 		return (-1);
757*99ebb4caSwyllys 
758*99ebb4caSwyllys 	state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
759*99ebb4caSwyllys 	    RDN_MIN, RDN_MAX);
760*99ebb4caSwyllys 	if (state == NULL) {
761*99ebb4caSwyllys 		goto out;
7627711facfSdinak 	}
7637711facfSdinak 
764*99ebb4caSwyllys 	locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
765*99ebb4caSwyllys 	org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
766*99ebb4caSwyllys 	unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
767*99ebb4caSwyllys 	name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
768*99ebb4caSwyllys 	email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
7697711facfSdinak 
770*99ebb4caSwyllys 	/* Now create a subject name from the input strings */
771*99ebb4caSwyllys 	if ((subname = malloc(SUBNAMESIZ)) == NULL)
772*99ebb4caSwyllys 		goto out;
773*99ebb4caSwyllys 
774*99ebb4caSwyllys 	(void) memset(subname, 0, SUBNAMESIZ);
775*99ebb4caSwyllys 	(void) strlcpy(subname, "C=", SUBNAMESIZ);
776*99ebb4caSwyllys 	(void) strlcat(subname, country, SUBNAMESIZ);
777*99ebb4caSwyllys 	(void) strlcat(subname, ", ", SUBNAMESIZ);
778*99ebb4caSwyllys 	(void) strlcat(subname, "ST=", SUBNAMESIZ);
779*99ebb4caSwyllys 	(void) strlcat(subname, state, SUBNAMESIZ);
7807711facfSdinak 
781*99ebb4caSwyllys 	if (locality) {
782*99ebb4caSwyllys 		(void) strlcat(subname, ", ", SUBNAMESIZ);
783*99ebb4caSwyllys 		(void) strlcat(subname, "L=", SUBNAMESIZ);
784*99ebb4caSwyllys 		(void) strlcat(subname, locality, SUBNAMESIZ);
7857711facfSdinak 	}
7867711facfSdinak 
787*99ebb4caSwyllys 	if (org) {
788*99ebb4caSwyllys 		(void) strlcat(subname, ", ", SUBNAMESIZ);
789*99ebb4caSwyllys 		(void) strlcat(subname, "O=", SUBNAMESIZ);
790*99ebb4caSwyllys 		(void) strlcat(subname, org, SUBNAMESIZ);
7917711facfSdinak 	}
7927711facfSdinak 
793*99ebb4caSwyllys 	if (unit) {
794*99ebb4caSwyllys 		(void) strlcat(subname, ", ", SUBNAMESIZ);
795*99ebb4caSwyllys 		(void) strlcat(subname, "OU=", SUBNAMESIZ);
796*99ebb4caSwyllys 		(void) strlcat(subname, unit, SUBNAMESIZ);
797*99ebb4caSwyllys 	}
7987711facfSdinak 
799*99ebb4caSwyllys 	if (name) {
800*99ebb4caSwyllys 		(void) strlcat(subname, ", ", SUBNAMESIZ);
801*99ebb4caSwyllys 		(void) strlcat(subname, "CN=", SUBNAMESIZ);
802*99ebb4caSwyllys 		(void) strlcat(subname, name, SUBNAMESIZ);
8037711facfSdinak 	}
8047711facfSdinak 
805*99ebb4caSwyllys 	if (email) {
806*99ebb4caSwyllys 		(void) strlcat(subname, ", ", SUBNAMESIZ);
807*99ebb4caSwyllys 		(void) strlcat(subname, "E=", SUBNAMESIZ);
808*99ebb4caSwyllys 		(void) strlcat(subname, email, SUBNAMESIZ);
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 
811*99ebb4caSwyllys out:
812*99ebb4caSwyllys 	if (country)
813*99ebb4caSwyllys 		free(country);
814*99ebb4caSwyllys 	if (state)
815*99ebb4caSwyllys 		free(state);
816*99ebb4caSwyllys 	if (locality)
817*99ebb4caSwyllys 		free(locality);
818*99ebb4caSwyllys 	if (org)
819*99ebb4caSwyllys 		free(org);
820*99ebb4caSwyllys 	if (unit)
821*99ebb4caSwyllys 		free(unit);
822*99ebb4caSwyllys 	if (name)
823*99ebb4caSwyllys 		free(name);
824*99ebb4caSwyllys 	if (email)
825*99ebb4caSwyllys 		free(email);
826*99ebb4caSwyllys 
827*99ebb4caSwyllys 	if (subname == NULL)
828*99ebb4caSwyllys 		return (-1);
829*99ebb4caSwyllys 	else {
830*99ebb4caSwyllys 		*result = subname;
831*99ebb4caSwyllys 		return (0);
8327711facfSdinak 	}
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate /*
836*99ebb4caSwyllys  * Parse a string of KeyUsage values and convert
837*99ebb4caSwyllys  * them to the correct KU Bits.
838*99ebb4caSwyllys  * The field may be marked "critical" by prepending
839*99ebb4caSwyllys  * "critical:" to the list.
840*99ebb4caSwyllys  * EX:  critical:digitialSignature,keyEncipherment
8417c478bd9Sstevel@tonic-gate  */
842*99ebb4caSwyllys KMF_RETURN
843*99ebb4caSwyllys verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
8447c478bd9Sstevel@tonic-gate {
845*99ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
846*99ebb4caSwyllys 	uint16_t kuval;
847*99ebb4caSwyllys 	char *k;
848*99ebb4caSwyllys 
849*99ebb4caSwyllys 	*kubits = 0;
850*99ebb4caSwyllys 	if (kustr == NULL || !strlen(kustr))
851*99ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
852*99ebb4caSwyllys 
853*99ebb4caSwyllys 	/* Check to see if this is critical */
854*99ebb4caSwyllys 	if (!strncasecmp(kustr, "critical:", strlen("critical:"))) {
855*99ebb4caSwyllys 		*critical = TRUE;
856*99ebb4caSwyllys 		kustr += strlen("critical:");
857*99ebb4caSwyllys 	} else {
858*99ebb4caSwyllys 		*critical = FALSE;
8597c478bd9Sstevel@tonic-gate 	}
8607711facfSdinak 
861*99ebb4caSwyllys 	k = strtok(kustr, ",");
862*99ebb4caSwyllys 	while (k != NULL) {
863*99ebb4caSwyllys 		kuval = KMF_StringToKeyUsage(k);
864*99ebb4caSwyllys 		if (kuval == 0) {
865*99ebb4caSwyllys 			*kubits = 0;
866*99ebb4caSwyllys 			return (KMF_ERR_BAD_PARAMETER);
8677711facfSdinak 		}
868*99ebb4caSwyllys 		*kubits |= kuval;
869*99ebb4caSwyllys 		k = strtok(NULL, ",");
8707711facfSdinak 	}
8717711facfSdinak 
872*99ebb4caSwyllys 	return (ret);
8737711facfSdinak }
8747711facfSdinak 
8757711facfSdinak /*
876*99ebb4caSwyllys  * Verify the alternate subject label is real or invalid.
877*99ebb4caSwyllys  *
878*99ebb4caSwyllys  * The field may be marked "critical" by prepending
879*99ebb4caSwyllys  * "critical:" to the list.
880*99ebb4caSwyllys  * EX:  "critical:IP=1.2.3.4"
8817711facfSdinak  */
882*99ebb4caSwyllys KMF_RETURN
883*99ebb4caSwyllys verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
8847711facfSdinak {
885*99ebb4caSwyllys 	char *p;
886*99ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
8877711facfSdinak 
888*99ebb4caSwyllys 	/* Check to see if this is critical */
889*99ebb4caSwyllys 	if (!strncasecmp(arg, "critical:", strlen("critical:"))) {
890*99ebb4caSwyllys 		*critical = TRUE;
891*99ebb4caSwyllys 		arg += strlen("critical:");
892*99ebb4caSwyllys 	} else {
893*99ebb4caSwyllys 		*critical = FALSE;
894*99ebb4caSwyllys 	}
8957711facfSdinak 
896*99ebb4caSwyllys 	/* Make sure there is an "=" sign */
897*99ebb4caSwyllys 	p = strchr(arg, '=');
898*99ebb4caSwyllys 	if (p == NULL)
899*99ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
9007711facfSdinak 
901*99ebb4caSwyllys 	p[0] = '\0';
902*99ebb4caSwyllys 
903*99ebb4caSwyllys 	if (strcmp(arg, "IP") == 0)
904*99ebb4caSwyllys 		*type = GENNAME_IPADDRESS;
905*99ebb4caSwyllys 	else if (strcmp(arg, "DNS") == 0)
906*99ebb4caSwyllys 		*type = GENNAME_DNSNAME;
907*99ebb4caSwyllys 	else if (strcmp(arg, "EMAIL") == 0)
908*99ebb4caSwyllys 		*type = GENNAME_RFC822NAME;
909*99ebb4caSwyllys 	else if (strcmp(arg, "URI") == 0)
910*99ebb4caSwyllys 		*type = GENNAME_URI;
911*99ebb4caSwyllys 	else if (strcmp(arg, "DN") == 0)
912*99ebb4caSwyllys 		*type = GENNAME_DIRECTORYNAME;
913*99ebb4caSwyllys 	else if (strcmp(arg, "RID") == 0)
914*99ebb4caSwyllys 		*type = GENNAME_REGISTEREDID;
915*99ebb4caSwyllys 	else
916*99ebb4caSwyllys 		rv = KMF_ERR_BAD_PARAMETER;
917*99ebb4caSwyllys 
918*99ebb4caSwyllys 	p[0] = '=';
919*99ebb4caSwyllys 
920*99ebb4caSwyllys 	return (rv);
9217c478bd9Sstevel@tonic-gate }
92249e21299Sdinak 
923*99ebb4caSwyllys int
924*99ebb4caSwyllys get_token_password(KMF_KEYSTORE_TYPE kstype,
925*99ebb4caSwyllys 	char *token_spec, KMF_CREDENTIAL *cred)
92649e21299Sdinak {
927*99ebb4caSwyllys 	char	prompt[1024];
928*99ebb4caSwyllys 	char	*p = NULL;
92949e21299Sdinak 
930*99ebb4caSwyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
931*99ebb4caSwyllys 		p = strchr(token_spec, ':');
932*99ebb4caSwyllys 		if (p != NULL)
933*99ebb4caSwyllys 		*p = 0;
934*99ebb4caSwyllys 	}
93549e21299Sdinak 	/*
936*99ebb4caSwyllys 	 * Login to the token first.
93749e21299Sdinak 	 */
938*99ebb4caSwyllys 	(void) snprintf(prompt, sizeof (prompt),
939*99ebb4caSwyllys 		gettext(DEFAULT_TOKEN_PROMPT),
940*99ebb4caSwyllys 		token_spec);
94149e21299Sdinak 
942*99ebb4caSwyllys 	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
943*99ebb4caSwyllys 		(ulong_t *)&cred->credlen) != CKR_OK) {
944*99ebb4caSwyllys 		cred->cred = NULL;
945*99ebb4caSwyllys 		cred->credlen = 0;
94649e21299Sdinak 	}
94749e21299Sdinak 
948*99ebb4caSwyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
949*99ebb4caSwyllys 		*p = ':';
950*99ebb4caSwyllys 	return (KMF_OK);
95149e21299Sdinak }
95249e21299Sdinak 
953*99ebb4caSwyllys KMF_RETURN
954*99ebb4caSwyllys verify_file(char *filename)
95549e21299Sdinak {
956*99ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
957*99ebb4caSwyllys 	int fd;
95849e21299Sdinak 
959*99ebb4caSwyllys 	/*
960*99ebb4caSwyllys 	 * Attempt to open with  the EXCL flag so that if
961*99ebb4caSwyllys 	 * it already exists, the open will fail.  It will
962*99ebb4caSwyllys 	 * also fail if the file cannot be created due to
963*99ebb4caSwyllys 	 * permissions on the parent directory, or if the
964*99ebb4caSwyllys 	 * parent directory itself does not exist.
965*99ebb4caSwyllys 	 */
966*99ebb4caSwyllys 	fd = open(filename, O_CREAT | O_EXCL, 0600);
967*99ebb4caSwyllys 	if (fd == -1)
968*99ebb4caSwyllys 		return (KMF_ERR_OPEN_FILE);
96949e21299Sdinak 
970*99ebb4caSwyllys 	/* If we were able to create it, delete it. */
971*99ebb4caSwyllys 	(void) close(fd);
972*99ebb4caSwyllys 	(void) unlink(filename);
97349e21299Sdinak 
974*99ebb4caSwyllys 	return (ret);
975*99ebb4caSwyllys }
97649e21299Sdinak 
977*99ebb4caSwyllys void
978*99ebb4caSwyllys display_error(void *handle, KMF_RETURN errcode, char *prefix)
979*99ebb4caSwyllys {
980*99ebb4caSwyllys 	KMF_RETURN rv1, rv2;
981*99ebb4caSwyllys 	char *plugin_errmsg = NULL;
982*99ebb4caSwyllys 	char *kmf_errmsg = NULL;
98349e21299Sdinak 
984*99ebb4caSwyllys 	rv1 = KMF_GetPluginErrorString(handle, &plugin_errmsg);
985*99ebb4caSwyllys 	rv2 = KMF_GetKMFErrorString(errcode, &kmf_errmsg);
98649e21299Sdinak 
987*99ebb4caSwyllys 	cryptoerror(LOG_STDERR, "%s:", prefix);
988*99ebb4caSwyllys 	if (rv1 == KMF_OK && plugin_errmsg) {
989*99ebb4caSwyllys 		cryptoerror(LOG_STDERR,
990*99ebb4caSwyllys 			gettext("keystore error: %s"),
991*99ebb4caSwyllys 			plugin_errmsg);
992*99ebb4caSwyllys 		KMF_FreeString(plugin_errmsg);
993*99ebb4caSwyllys 	}
99449e21299Sdinak 
995*99ebb4caSwyllys 	if (rv2 == KMF_OK && kmf_errmsg) {
996*99ebb4caSwyllys 		cryptoerror(LOG_STDERR,
997*99ebb4caSwyllys 			gettext("libkmf error: %s"),
998*99ebb4caSwyllys 			kmf_errmsg);
999*99ebb4caSwyllys 		KMF_FreeString(kmf_errmsg);
100049e21299Sdinak 	}
100149e21299Sdinak 
1002*99ebb4caSwyllys 	if (rv1 != KMF_OK && rv2 != KMF_OK)
1003*99ebb4caSwyllys 		cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
1004*99ebb4caSwyllys 
100549e21299Sdinak }
1006