xref: /titanic_44/usr/src/cmd/cmd-crypto/pktool/common.c (revision 47e946e784719ae402ace34695f67b0e6e76ae5c)
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
599ebb4caSwyllys  * Common Development and Distribution License (the "License").
699ebb4caSwyllys  * 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*47e946e7SWyllys Ingersoll  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This file contains the functions that are shared among
287c478bd9Sstevel@tonic-gate  * the various services this tool will ultimately provide.
297711facfSdinak  * The functions in this file return PKCS#11 CK_RV errors.
307711facfSdinak  * Only one session and one login per token is supported
317711facfSdinak  * at this time.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
3899ebb4caSwyllys #include <sys/types.h>
3999ebb4caSwyllys #include <sys/stat.h>
4099ebb4caSwyllys #include <fcntl.h>
4199ebb4caSwyllys #include <tzfile.h>
427c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
437c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
4499ebb4caSwyllys #include <kmfapi.h>
457c478bd9Sstevel@tonic-gate 
4699ebb4caSwyllys #include "common.h"
477711facfSdinak 
487711facfSdinak /* Local status variables. */
497711facfSdinak static boolean_t	initialized = B_FALSE;
507711facfSdinak static boolean_t	session_opened = B_FALSE;
517711facfSdinak static boolean_t	logged_in = B_FALSE;
527c478bd9Sstevel@tonic-gate 
5349e21299Sdinak /* Supporting structures and global variables for getopt_av(). */
5449e21299Sdinak typedef struct	av_opts_s {
5549e21299Sdinak 	int		shortnm;	/* short name character */
5649e21299Sdinak 	char		*longnm;	/* long name string, NOT terminated */
5749e21299Sdinak 	int		longnm_len;	/* length of long name string */
5849e21299Sdinak 	boolean_t	has_arg;	/* takes optional argument */
5949e21299Sdinak } av_opts;
6049e21299Sdinak static av_opts		*opts_av = NULL;
6149e21299Sdinak static const char	*_save_optstr = NULL;
6249e21299Sdinak static int		_save_numopts = 0;
6349e21299Sdinak 
6449e21299Sdinak int			optind_av = 1;
6549e21299Sdinak char			*optarg_av = NULL;
6649e21299Sdinak 
6799ebb4caSwyllys static void close_sess(CK_SESSION_HANDLE);
6899ebb4caSwyllys static void logout_token(CK_SESSION_HANDLE);
6999ebb4caSwyllys 
707c478bd9Sstevel@tonic-gate /*
717711facfSdinak  * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
727711facfSdinak  * along with setting/resetting state variables.
737c478bd9Sstevel@tonic-gate  */
74448b8615Swyllys static CK_RV
75448b8615Swyllys init_pkcs11(void)
767c478bd9Sstevel@tonic-gate {
777711facfSdinak 	CK_RV		rv = CKR_OK;
787c478bd9Sstevel@tonic-gate 
797711facfSdinak 	/* If C_Initialize() already called, nothing to do here. */
807711facfSdinak 	if (initialized == B_TRUE)
817711facfSdinak 		return (CKR_OK);
827711facfSdinak 
837711facfSdinak 	/* Reset state variables because C_Initialize() not yet done. */
847711facfSdinak 	session_opened = B_FALSE;
857711facfSdinak 	logged_in = B_FALSE;
867711facfSdinak 
877c478bd9Sstevel@tonic-gate 	/* Initialize PKCS#11 library. */
887c478bd9Sstevel@tonic-gate 	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
897c478bd9Sstevel@tonic-gate 	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
907711facfSdinak 		return (rv);
917c478bd9Sstevel@tonic-gate 	}
927c478bd9Sstevel@tonic-gate 
937711facfSdinak 	initialized = B_TRUE;
947711facfSdinak 	return (CKR_OK);
957711facfSdinak }
967711facfSdinak 
977711facfSdinak /*
987711facfSdinak  * Finalize PKCS#11 library and reset state variables.  Open sessions,
997711facfSdinak  * if any, are closed, and thereby any logins are logged out also.
1007711facfSdinak  */
1017711facfSdinak void
1027711facfSdinak final_pk11(CK_SESSION_HANDLE sess)
1037711facfSdinak {
1047711facfSdinak 
1057711facfSdinak 	/* If the library wasn't initialized, nothing to do here. */
1067711facfSdinak 	if (!initialized)
1077711facfSdinak 		return;
1087711facfSdinak 
1097711facfSdinak 	/* Make sure the sesion is closed first. */
1107711facfSdinak 	close_sess(sess);
1117711facfSdinak 
1127711facfSdinak 	(void) C_Finalize(NULL);
1137711facfSdinak 	initialized = B_FALSE;
1147711facfSdinak }
1157711facfSdinak 
1167711facfSdinak /*
1177711facfSdinak  * Close PKCS#11 session and reset state variables.  Any logins are
1187711facfSdinak  * logged out.
1197711facfSdinak  */
12099ebb4caSwyllys static void
1217711facfSdinak close_sess(CK_SESSION_HANDLE sess)
1227711facfSdinak {
1237711facfSdinak 
1247711facfSdinak 	if (sess == NULL) {
1257711facfSdinak 		return;
1267711facfSdinak 	}
1277711facfSdinak 
1287711facfSdinak 	/* If session is already closed, nothing to do here. */
1297711facfSdinak 	if (!session_opened)
1307711facfSdinak 		return;
1317711facfSdinak 
1327711facfSdinak 	/* Make sure user is logged out of token. */
1337711facfSdinak 	logout_token(sess);
1347711facfSdinak 
1357711facfSdinak 	(void) C_CloseSession(sess);
1367711facfSdinak 	session_opened = B_FALSE;
1377711facfSdinak }
1387711facfSdinak 
1397711facfSdinak /*
1407711facfSdinak  * Log user out of token and reset status variable.
1417711facfSdinak  */
14299ebb4caSwyllys static void
1437711facfSdinak logout_token(CK_SESSION_HANDLE sess)
1447711facfSdinak {
1457711facfSdinak 
1467711facfSdinak 	if (sess == NULL) {
1477711facfSdinak 		return;
1487711facfSdinak 	}
1497711facfSdinak 
1507711facfSdinak 	/* If already logged out, nothing to do here. */
1517711facfSdinak 	if (!logged_in)
1527711facfSdinak 		return;
1537711facfSdinak 
1547711facfSdinak 	(void) C_Logout(sess);
1557711facfSdinak 	logged_in = B_FALSE;
1567711facfSdinak }
1577711facfSdinak 
1587711facfSdinak /*
1597711facfSdinak  * Gets PIN from user.  Caller needs to free the returned PIN when done.
1607711facfSdinak  * If two prompts are given, the PIN is confirmed with second prompt.
1617711facfSdinak  * Note that getphassphrase() may return data in static memory area.
1627711facfSdinak  */
1637711facfSdinak CK_RV
1647711facfSdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
1657711facfSdinak {
1667711facfSdinak 	char *save_phrase, *phrase1, *phrase2;
1677711facfSdinak 
1687711facfSdinak 	/* Prompt user for a PIN. */
1697711facfSdinak 	if (prompt1 == NULL) {
1707711facfSdinak 		return (CKR_ARGUMENTS_BAD);
1717711facfSdinak 	}
1727711facfSdinak 	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
1737711facfSdinak 		return (CKR_FUNCTION_FAILED);
1747711facfSdinak 	}
1757711facfSdinak 
1767711facfSdinak 	/* Duplicate 1st PIN in separate chunk of memory. */
1777711facfSdinak 	if ((save_phrase = strdup(phrase1)) == NULL)
1787711facfSdinak 		return (CKR_HOST_MEMORY);
1797711facfSdinak 
1807711facfSdinak 	/* If second prompt given, PIN confirmation is requested. */
1817711facfSdinak 	if (prompt2 != NULL) {
1827711facfSdinak 		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
1837711facfSdinak 			free(save_phrase);
1847711facfSdinak 			return (CKR_FUNCTION_FAILED);
1857711facfSdinak 		}
1867711facfSdinak 		if (strcmp(save_phrase, phrase2) != 0) {
1877711facfSdinak 			free(save_phrase);
1887711facfSdinak 			return (CKR_PIN_INCORRECT);
1897711facfSdinak 		}
1907711facfSdinak 	}
1917711facfSdinak 
1927711facfSdinak 	*pin = (CK_UTF8CHAR_PTR)save_phrase;
1937711facfSdinak 	*pinlen = strlen(save_phrase);
1947711facfSdinak 	return (CKR_OK);
1957711facfSdinak }
1967711facfSdinak 
197d00756ccSwyllys int
198d00756ccSwyllys yn_to_int(char *ynstr)
199d00756ccSwyllys {
200d00756ccSwyllys 	char *y = gettext("yes");
201d00756ccSwyllys 	char *n = gettext("no");
202d00756ccSwyllys 	if (ynstr == NULL)
203d00756ccSwyllys 		return (-1);
204d00756ccSwyllys 
205d00756ccSwyllys 	if (strncasecmp(ynstr, y, 1) == 0)
206d00756ccSwyllys 		return (1);
207d00756ccSwyllys 	else if (strncasecmp(ynstr, n, 1) == 0)
208d00756ccSwyllys 		return (0);
209d00756ccSwyllys 	else
210d00756ccSwyllys 		return (-1);
211d00756ccSwyllys }
212d00756ccSwyllys 
2137711facfSdinak /*
2147711facfSdinak  * Gets yes/no response from user.  If either no prompt is supplied, a
2157711facfSdinak  * default prompt is used.  If not message for invalid input is supplied,
2167711facfSdinak  * a default will not be provided.  If the user provides no response,
2177711facfSdinak  * the input default B_TRUE == yes, B_FALSE == no is returned.
2187711facfSdinak  * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
2197711facfSdinak  */
2207711facfSdinak boolean_t
2217711facfSdinak yesno(char *prompt, char *invalid, boolean_t dflt)
2227711facfSdinak {
2237711facfSdinak 	char	*response, buf[1024];
224d00756ccSwyllys 	int	ans;
2257711facfSdinak 
2267711facfSdinak 	if (prompt == NULL)
2277711facfSdinak 		prompt = gettext("Enter (y)es or (n)o? ");
2287711facfSdinak 
2297711facfSdinak 	for (;;) {
2307711facfSdinak 		/* Prompt user. */
2317711facfSdinak 		(void) printf("%s", prompt);
2327711facfSdinak 		(void) fflush(stdout);
2337711facfSdinak 
2347711facfSdinak 		/* Get the response. */
2357711facfSdinak 		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
2367711facfSdinak 			break;		/* go to default response */
2377711facfSdinak 
2387711facfSdinak 		/* Skip any leading white space. */
2397711facfSdinak 		while (isspace(*response))
2407711facfSdinak 			response++;
2417711facfSdinak 		if (*response == '\0')
2427711facfSdinak 			break;		/* go to default response */
2437711facfSdinak 
244d00756ccSwyllys 		ans = yn_to_int(response);
245d00756ccSwyllys 		if (ans == 1)
2467711facfSdinak 			return (B_TRUE);
247d00756ccSwyllys 		else if (ans == 0)
2487711facfSdinak 			return (B_FALSE);
2497711facfSdinak 
2507711facfSdinak 		/* Indicate invalid input, and try again. */
2517711facfSdinak 		if (invalid != NULL)
2527711facfSdinak 			(void) printf("%s", invalid);
2537711facfSdinak 	}
2547711facfSdinak 	return (dflt);
2557711facfSdinak }
2567711facfSdinak 
2577711facfSdinak /*
2587711facfSdinak  * Gets the list of slots which have tokens in them.  Keeps adjusting
2597711facfSdinak  * the size of the slot list buffer until the call is successful or an
2607711facfSdinak  * irrecoverable error occurs.
2617711facfSdinak  */
2627711facfSdinak CK_RV
2637711facfSdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
2647711facfSdinak {
2657711facfSdinak 	CK_ULONG	tmp_count = 0;
2667711facfSdinak 	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
2677711facfSdinak 	int		rv = CKR_OK;
2687711facfSdinak 
2697711facfSdinak 	if (!initialized)
270448b8615Swyllys 		if ((rv = init_pkcs11()) != CKR_OK)
2717711facfSdinak 			return (rv);
2727711facfSdinak 
2737711facfSdinak 	/*
2747711facfSdinak 	 * Get the slot count first because we don't know how many
2757711facfSdinak 	 * slots there are and how many of those slots even have tokens.
2767711facfSdinak 	 * Don't specify an arbitrary buffer size for the slot list;
2777711facfSdinak 	 * it may be too small (see section 11.5 of PKCS#11 spec).
2787711facfSdinak 	 * Also select only those slots that have tokens in them,
2797711facfSdinak 	 * because this tool has no need to know about empty slots.
2807711facfSdinak 	 */
2817711facfSdinak 	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
2827711facfSdinak 		return (rv);
2837711facfSdinak 
2847711facfSdinak 	if (tmp_count == 0) {
2857711facfSdinak 		*slot_list = NULL_PTR;
2867711facfSdinak 		*slot_count = 0;
2877711facfSdinak 		return (CKR_OK);
2887711facfSdinak 	}
2897711facfSdinak 
2907711facfSdinak 	/* Allocate initial space for the slot list. */
2917711facfSdinak 	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
2927711facfSdinak 	    sizeof (CK_SLOT_ID))) == NULL)
2937711facfSdinak 		return (CKR_HOST_MEMORY);
2947711facfSdinak 
2957711facfSdinak 	/* Then get the slot list itself. */
2967711facfSdinak 	for (;;) {
2977711facfSdinak 		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
2987711facfSdinak 			*slot_list = tmp_list;
2997711facfSdinak 			*slot_count = tmp_count;
3007711facfSdinak 			break;
3017711facfSdinak 		}
3027711facfSdinak 
3037711facfSdinak 		if (rv != CKR_BUFFER_TOO_SMALL) {
3047711facfSdinak 			free(tmp_list);
3057711facfSdinak 			break;
3067711facfSdinak 		}
3077711facfSdinak 
3087711facfSdinak 		/* If the number of slots grew, try again. */
3097711facfSdinak 		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
3107711facfSdinak 		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
3117711facfSdinak 			free(tmp_list);
3127711facfSdinak 			rv = CKR_HOST_MEMORY;
3137711facfSdinak 			break;
3147711facfSdinak 		}
3157711facfSdinak 		tmp_list = tmp2_list;
3167711facfSdinak 	}
3177711facfSdinak 
3187711facfSdinak 	return (rv);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
32249e21299Sdinak  * Breaks out the getopt-style option string into a structure that can be
32349e21299Sdinak  * traversed later for calls to getopt_av().  Option string is NOT altered,
32449e21299Sdinak  * but the struct fields point to locations within option string.
32549e21299Sdinak  */
32649e21299Sdinak static int
32749e21299Sdinak populate_opts(char *optstring)
32849e21299Sdinak {
32949e21299Sdinak 	int		i;
33049e21299Sdinak 	av_opts		*temp;
33149e21299Sdinak 	char		*marker;
33249e21299Sdinak 
33349e21299Sdinak 	if (optstring == NULL || *optstring == '\0')
33449e21299Sdinak 		return (0);
33549e21299Sdinak 
33649e21299Sdinak 	/*
33749e21299Sdinak 	 * This tries to imitate getopt(3c) Each option must conform to:
33849e21299Sdinak 	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
33949e21299Sdinak 	 * If long name is missing, the short name is used for long name.
34049e21299Sdinak 	 */
34149e21299Sdinak 	for (i = 0; *optstring != '\0'; i++) {
34249e21299Sdinak 		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
34349e21299Sdinak 		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
34499ebb4caSwyllys 			if (opts_av != NULL)
34549e21299Sdinak 				free(opts_av);
34649e21299Sdinak 			opts_av = NULL;
34749e21299Sdinak 			return (0);
34899ebb4caSwyllys 		} else {
34949e21299Sdinak 			opts_av = (av_opts *)temp;
35099ebb4caSwyllys 		}
35149e21299Sdinak 
35299ebb4caSwyllys 		(void) memset(&opts_av[i], 0, sizeof (av_opts));
35349e21299Sdinak 		marker = optstring;		/* may need optstring later */
35449e21299Sdinak 
35549e21299Sdinak 		opts_av[i].shortnm = *marker++;	/* set short name */
35649e21299Sdinak 
35749e21299Sdinak 		if (*marker == ':') {		/* check for opt arg */
35849e21299Sdinak 			marker++;
35949e21299Sdinak 			opts_av[i].has_arg = B_TRUE;
36049e21299Sdinak 		}
36149e21299Sdinak 
36249e21299Sdinak 		if (*marker == '(') {		/* check and set long name */
36349e21299Sdinak 			marker++;
36449e21299Sdinak 			opts_av[i].longnm = marker;
36549e21299Sdinak 			opts_av[i].longnm_len = strcspn(marker, ")");
36649e21299Sdinak 			optstring = marker + opts_av[i].longnm_len + 1;
36749e21299Sdinak 		} else {
36849e21299Sdinak 			/* use short name option character */
36949e21299Sdinak 			opts_av[i].longnm = optstring;
37049e21299Sdinak 			opts_av[i].longnm_len = 1;
37149e21299Sdinak 			optstring = marker;
37249e21299Sdinak 		}
37349e21299Sdinak 	}
37449e21299Sdinak 
37549e21299Sdinak 	return (i);
37649e21299Sdinak }
37749e21299Sdinak 
37849e21299Sdinak /*
37949e21299Sdinak  * getopt_av() is very similar to getopt(3c) in that the takes an option
38049e21299Sdinak  * string, compares command line arguments for matches, and returns a single
38149e21299Sdinak  * letter option when a match is found.  However, getopt_av() differs from
38249e21299Sdinak  * getopt(3c) by requiring that only longname options and values be found
38349e21299Sdinak  * on the command line and all leading dashes are omitted.  In other words,
38449e21299Sdinak  * it tries to enforce only longname "option=value" arguments on the command
38549e21299Sdinak  * line.  Boolean options are not allowed either.
38649e21299Sdinak  */
38749e21299Sdinak int
38849e21299Sdinak getopt_av(int argc, char * const *argv, const char *optstring)
38949e21299Sdinak {
39049e21299Sdinak 	int	i;
39149e21299Sdinak 	int	len;
39299ebb4caSwyllys 	char   *cur_option;
39349e21299Sdinak 
39449e21299Sdinak 	if (optind_av >= argc)
39549e21299Sdinak 		return (EOF);
39649e21299Sdinak 
39749e21299Sdinak 	/* First time or when optstring changes from previous one */
39849e21299Sdinak 	if (_save_optstr != optstring) {
39949e21299Sdinak 		if (opts_av != NULL)
40049e21299Sdinak 			free(opts_av);
40149e21299Sdinak 		opts_av = NULL;
40249e21299Sdinak 		_save_optstr = optstring;
40349e21299Sdinak 		_save_numopts = populate_opts((char *)optstring);
40449e21299Sdinak 	}
40549e21299Sdinak 
40649e21299Sdinak 	for (i = 0; i < _save_numopts; i++) {
40799ebb4caSwyllys 		cur_option = argv[optind_av];
40899ebb4caSwyllys 
40999ebb4caSwyllys 		if (strcmp(cur_option, "--") == 0) {
41049e21299Sdinak 			optind_av++;
41149e21299Sdinak 			break;
41249e21299Sdinak 		}
41349e21299Sdinak 
41499ebb4caSwyllys 		if (cur_option[0] == '-' && strlen(cur_option) == 2) {
41599ebb4caSwyllys 			len = 1;
41699ebb4caSwyllys 			cur_option++; /* remove "-" */
41799ebb4caSwyllys 		} else {
41899ebb4caSwyllys 			len = strcspn(cur_option, "=");
41999ebb4caSwyllys 		}
42049e21299Sdinak 
42199ebb4caSwyllys 		if (len == opts_av[i].longnm_len && strncmp(cur_option,
42249e21299Sdinak 		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
42349e21299Sdinak 			/* matched */
42449e21299Sdinak 			if (!opts_av[i].has_arg) {
42549e21299Sdinak 				optind_av++;
42649e21299Sdinak 				return (opts_av[i].shortnm);
42749e21299Sdinak 			}
42849e21299Sdinak 
42949e21299Sdinak 			/* needs optarg */
43099ebb4caSwyllys 			if (cur_option[len] == '=') {
43199ebb4caSwyllys 				optarg_av = &(cur_option[len+1]);
43249e21299Sdinak 				optind_av++;
43349e21299Sdinak 				return (opts_av[i].shortnm);
43449e21299Sdinak 			}
43549e21299Sdinak 
43649e21299Sdinak 			optarg_av = NULL;
43749e21299Sdinak 			optind_av++;
43849e21299Sdinak 			return ((int)'?');
43949e21299Sdinak 		}
44049e21299Sdinak 	}
44149e21299Sdinak 
44249e21299Sdinak 	return (EOF);
44349e21299Sdinak }
44499ebb4caSwyllys 
44599ebb4caSwyllys KMF_KEYSTORE_TYPE
44699ebb4caSwyllys KS2Int(char *keystore_str)
44799ebb4caSwyllys {
44899ebb4caSwyllys 	if (keystore_str == NULL)
44999ebb4caSwyllys 		return (0);
450d00756ccSwyllys 	if (strcasecmp(keystore_str, "pkcs11") == 0)
45199ebb4caSwyllys 		return (KMF_KEYSTORE_PK11TOKEN);
452d00756ccSwyllys 	else if (strcasecmp(keystore_str, "nss") == 0)
45399ebb4caSwyllys 		return (KMF_KEYSTORE_NSS);
454d00756ccSwyllys 	else if (strcasecmp(keystore_str, "file") == 0)
45599ebb4caSwyllys 		return (KMF_KEYSTORE_OPENSSL);
45699ebb4caSwyllys 	else
45799ebb4caSwyllys 		return (0);
45899ebb4caSwyllys }
45999ebb4caSwyllys 
46099ebb4caSwyllys 
46199ebb4caSwyllys int
46299ebb4caSwyllys Str2KeyType(char *algm, KMF_KEY_ALG *ktype, KMF_ALGORITHM_INDEX *sigAlg)
46399ebb4caSwyllys {
46499ebb4caSwyllys 	if (algm == NULL) {
46599ebb4caSwyllys 		*sigAlg = KMF_ALGID_MD5WithRSA;
46699ebb4caSwyllys 		*ktype = KMF_RSA;
46799ebb4caSwyllys 	} else if (strcasecmp(algm, "DSA") == 0) {
46899ebb4caSwyllys 		*sigAlg = KMF_ALGID_SHA1WithDSA;
46999ebb4caSwyllys 		*ktype = KMF_DSA;
47099ebb4caSwyllys 	} else if (strcasecmp(algm, "RSA") == 0) {
47199ebb4caSwyllys 		*sigAlg = KMF_ALGID_MD5WithRSA;
47299ebb4caSwyllys 		*ktype = KMF_RSA;
47399ebb4caSwyllys 	} else {
47499ebb4caSwyllys 		return (-1);
47599ebb4caSwyllys 	}
47699ebb4caSwyllys 	return (0);
47799ebb4caSwyllys }
47899ebb4caSwyllys 
47999ebb4caSwyllys int
48099ebb4caSwyllys Str2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
48199ebb4caSwyllys {
48299ebb4caSwyllys 	if (algm == NULL)
48399ebb4caSwyllys 		*ktype = KMF_AES;
48499ebb4caSwyllys 	else if (strcasecmp(algm, "aes") == 0)
48599ebb4caSwyllys 		*ktype = KMF_AES;
48699ebb4caSwyllys 	else if (strcasecmp(algm, "arcfour") == 0)
48799ebb4caSwyllys 		*ktype = KMF_RC4;
48899ebb4caSwyllys 	else if (strcasecmp(algm, "des") == 0)
48999ebb4caSwyllys 		*ktype = KMF_DES;
49099ebb4caSwyllys 	else if (strcasecmp(algm, "3des") == 0)
49199ebb4caSwyllys 		*ktype = KMF_DES3;
492c197cb9dShylee 	else if (strcasecmp(algm, "generic") == 0)
493c197cb9dShylee 		*ktype = KMF_GENERIC_SECRET;
49499ebb4caSwyllys 	else
49599ebb4caSwyllys 		return (-1);
49699ebb4caSwyllys 
49799ebb4caSwyllys 	return (0);
49899ebb4caSwyllys }
49999ebb4caSwyllys 
50099ebb4caSwyllys int
50199ebb4caSwyllys Str2Lifetime(char *ltimestr, uint32_t *ltime)
50299ebb4caSwyllys {
50399ebb4caSwyllys 	int num;
50499ebb4caSwyllys 	char timetok[6];
50599ebb4caSwyllys 
506d00756ccSwyllys 	if (ltimestr == NULL || strlen(ltimestr) == 0) {
50799ebb4caSwyllys 		/* default to 1 year lifetime */
50899ebb4caSwyllys 		*ltime = SECSPERDAY * DAYSPERNYEAR;
50999ebb4caSwyllys 		return (0);
51099ebb4caSwyllys 	}
51199ebb4caSwyllys 
51299ebb4caSwyllys 	(void) memset(timetok, 0, sizeof (timetok));
51399ebb4caSwyllys 	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
51499ebb4caSwyllys 		return (-1);
51599ebb4caSwyllys 
516d00756ccSwyllys 	if (strcasecmp(timetok, "day") == 0||
517d00756ccSwyllys 	    strcasecmp(timetok, "days") == 0) {
51899ebb4caSwyllys 		*ltime = num * SECSPERDAY;
519d00756ccSwyllys 	} else if (strcasecmp(timetok, "hour") == 0||
520d00756ccSwyllys 	    strcasecmp(timetok, "hours") == 0) {
52199ebb4caSwyllys 		*ltime = num * SECSPERHOUR;
522d00756ccSwyllys 	} else if (strcasecmp(timetok, "year") == 0 ||
523d00756ccSwyllys 	    strcasecmp(timetok, "years") == 0) {
52499ebb4caSwyllys 		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
52599ebb4caSwyllys 	} else {
52699ebb4caSwyllys 		*ltime = 0;
52799ebb4caSwyllys 		return (-1);
52899ebb4caSwyllys 	}
52999ebb4caSwyllys 
53099ebb4caSwyllys 	return (0);
53199ebb4caSwyllys }
53299ebb4caSwyllys 
53399ebb4caSwyllys int
53499ebb4caSwyllys OT2Int(char *objclass)
53599ebb4caSwyllys {
53699ebb4caSwyllys 	char *c = NULL;
53799ebb4caSwyllys 	int retval = 0;
53899ebb4caSwyllys 
53999ebb4caSwyllys 	if (objclass == NULL)
54099ebb4caSwyllys 		return (-1);
54199ebb4caSwyllys 
54299ebb4caSwyllys 	c = strchr(objclass, ':');
54399ebb4caSwyllys 	if (c != NULL) {
544d00756ccSwyllys 		if (strcasecmp(c, ":private") == 0)
54599ebb4caSwyllys 			retval = PK_PRIVATE_OBJ;
546d00756ccSwyllys 		else if (strcasecmp(c, ":public") == 0)
54799ebb4caSwyllys 			retval = PK_PUBLIC_OBJ;
548d00756ccSwyllys 		else if (strcasecmp(c, ":both") == 0)
54999ebb4caSwyllys 			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
55099ebb4caSwyllys 		else /* unrecognized option */
55199ebb4caSwyllys 			return (-1);
55299ebb4caSwyllys 
55399ebb4caSwyllys 		*c = '\0';
55499ebb4caSwyllys 	}
55599ebb4caSwyllys 
556d00756ccSwyllys 	if (strcasecmp(objclass, "public") == 0) {
55799ebb4caSwyllys 		if (retval)
55899ebb4caSwyllys 			return (-1);
55930a5e8faSwyllys 		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
560d00756ccSwyllys 	} else if (strcasecmp(objclass, "private") == 0) {
56199ebb4caSwyllys 		if (retval)
56299ebb4caSwyllys 			return (-1);
56399ebb4caSwyllys 		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
564d00756ccSwyllys 	} else if (strcasecmp(objclass, "both") == 0) {
56599ebb4caSwyllys 		if (retval)
56699ebb4caSwyllys 			return (-1);
56799ebb4caSwyllys 		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
568d00756ccSwyllys 	} else if (strcasecmp(objclass, "cert") == 0) {
56999ebb4caSwyllys 		return (retval | PK_CERT_OBJ);
570d00756ccSwyllys 	} else if (strcasecmp(objclass, "key") == 0) {
57199ebb4caSwyllys 		if (retval == 0) /* return all keys */
57299ebb4caSwyllys 			return (retval | PK_KEY_OBJ);
57399ebb4caSwyllys 		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
57499ebb4caSwyllys 			/* return all keys */
57599ebb4caSwyllys 			return (retval | PK_KEY_OBJ);
57699ebb4caSwyllys 		else if (retval & PK_PUBLIC_OBJ)
57799ebb4caSwyllys 			/* Only return public keys */
57899ebb4caSwyllys 			return (retval | PK_PUBKEY_OBJ);
57999ebb4caSwyllys 		else if (retval & PK_PRIVATE_OBJ)
58099ebb4caSwyllys 			/* Only return private keys */
58199ebb4caSwyllys 			return (retval | PK_PRIKEY_OBJ);
582d00756ccSwyllys 	} else if (strcasecmp(objclass, "crl") == 0) {
58399ebb4caSwyllys 		if (retval)
58499ebb4caSwyllys 			return (-1);
58599ebb4caSwyllys 		return (retval | PK_CRL_OBJ);
58699ebb4caSwyllys 	}
58799ebb4caSwyllys 
58899ebb4caSwyllys 	if (retval == 0) /* No matches found */
58999ebb4caSwyllys 		retval = -1;
59099ebb4caSwyllys 	return (retval);
59199ebb4caSwyllys }
59299ebb4caSwyllys 
59399ebb4caSwyllys KMF_ENCODE_FORMAT
59499ebb4caSwyllys Str2Format(char *formstr)
59599ebb4caSwyllys {
596d00756ccSwyllys 	if (formstr == NULL || strcasecmp(formstr, "der") == 0)
59799ebb4caSwyllys 		return (KMF_FORMAT_ASN1);
598d00756ccSwyllys 	if (strcasecmp(formstr, "pem") == 0)
59999ebb4caSwyllys 		return (KMF_FORMAT_PEM);
600d00756ccSwyllys 	if (strcasecmp(formstr, "pkcs12") == 0)
60199ebb4caSwyllys 		return (KMF_FORMAT_PKCS12);
602d00756ccSwyllys 	if (strcasecmp(formstr, "raw") == 0)
60330a5e8faSwyllys 		return (KMF_FORMAT_RAWKEY);
60499ebb4caSwyllys 
60599ebb4caSwyllys 	return (KMF_FORMAT_UNDEF);
60699ebb4caSwyllys }
60799ebb4caSwyllys 
60899ebb4caSwyllys KMF_RETURN
609d00756ccSwyllys select_token(void *kmfhandle, char *token, int readonly)
61099ebb4caSwyllys {
61130a5e8faSwyllys 	KMF_ATTRIBUTE attlist[10];
61230a5e8faSwyllys 	int i = 0;
61330a5e8faSwyllys 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
61499ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
61599ebb4caSwyllys 
61699ebb4caSwyllys 	if (token == NULL)
61799ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
61899ebb4caSwyllys 
61930a5e8faSwyllys 	kmf_set_attr_at_index(attlist, i,
62030a5e8faSwyllys 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
62130a5e8faSwyllys 	    sizeof (kstype));
62230a5e8faSwyllys 	i++;
62399ebb4caSwyllys 
62430a5e8faSwyllys 	if (token) {
62530a5e8faSwyllys 		kmf_set_attr_at_index(attlist, i,
62630a5e8faSwyllys 		    KMF_TOKEN_LABEL_ATTR, token,
62730a5e8faSwyllys 		    strlen(token));
62830a5e8faSwyllys 		i++;
62930a5e8faSwyllys 	}
63030a5e8faSwyllys 
63130a5e8faSwyllys 	kmf_set_attr_at_index(attlist, i,
63230a5e8faSwyllys 	    KMF_READONLY_ATTR, &readonly,
63330a5e8faSwyllys 	    sizeof (readonly));
63430a5e8faSwyllys 	i++;
63530a5e8faSwyllys 
63630a5e8faSwyllys 	rv = kmf_configure_keystore(kmfhandle, i, attlist);
63799ebb4caSwyllys 	if (rv == KMF_ERR_TOKEN_SELECTED)
63899ebb4caSwyllys 		rv = KMF_OK;
63999ebb4caSwyllys 	return (rv);
64099ebb4caSwyllys }
64199ebb4caSwyllys 
64299ebb4caSwyllys KMF_RETURN
64399ebb4caSwyllys configure_nss(void *kmfhandle, char *dir, char *prefix)
64499ebb4caSwyllys {
64530a5e8faSwyllys 	KMF_ATTRIBUTE attlist[10];
64630a5e8faSwyllys 	int i = 0;
64730a5e8faSwyllys 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
64899ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
64999ebb4caSwyllys 
65030a5e8faSwyllys 	kmf_set_attr_at_index(attlist, i,
65130a5e8faSwyllys 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
65230a5e8faSwyllys 	    sizeof (kstype));
65330a5e8faSwyllys 	i++;
65499ebb4caSwyllys 
65530a5e8faSwyllys 	if (dir) {
65630a5e8faSwyllys 		kmf_set_attr_at_index(attlist, i,
65730a5e8faSwyllys 		    KMF_DIRPATH_ATTR, dir,
65830a5e8faSwyllys 		    strlen(dir));
65930a5e8faSwyllys 		i++;
66030a5e8faSwyllys 	}
66130a5e8faSwyllys 
66230a5e8faSwyllys 	if (prefix) {
66330a5e8faSwyllys 		kmf_set_attr_at_index(attlist, i,
66430a5e8faSwyllys 		    KMF_CERTPREFIX_ATTR, prefix,
66530a5e8faSwyllys 		    strlen(prefix));
66630a5e8faSwyllys 		i++;
66730a5e8faSwyllys 
66830a5e8faSwyllys 		kmf_set_attr_at_index(attlist, i,
66930a5e8faSwyllys 		    KMF_KEYPREFIX_ATTR, prefix,
67030a5e8faSwyllys 		    strlen(prefix));
67130a5e8faSwyllys 		i++;
67230a5e8faSwyllys 	}
67330a5e8faSwyllys 
67430a5e8faSwyllys 	rv = kmf_configure_keystore(kmfhandle, i, attlist);
67599ebb4caSwyllys 	if (rv == KMF_KEYSTORE_ALREADY_INITIALIZED)
67699ebb4caSwyllys 		rv = KMF_OK;
67799ebb4caSwyllys 
67899ebb4caSwyllys 	return (rv);
67999ebb4caSwyllys }
68099ebb4caSwyllys 
68199ebb4caSwyllys KMF_RETURN
68299ebb4caSwyllys get_pk12_password(KMF_CREDENTIAL *cred)
68399ebb4caSwyllys {
68499ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
68599ebb4caSwyllys 	char prompt[1024];
68699ebb4caSwyllys 
68799ebb4caSwyllys 	/*
68899ebb4caSwyllys 	 * Get the password to use for the PK12 encryption.
68999ebb4caSwyllys 	 */
69099ebb4caSwyllys 	(void) strlcpy(prompt,
69199ebb4caSwyllys 	    gettext("Enter password to use for "
69230a5e8faSwyllys 	    "accessing the PKCS12 file: "), sizeof (prompt));
69399ebb4caSwyllys 
69499ebb4caSwyllys 	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
69599ebb4caSwyllys 	    (ulong_t *)&cred->credlen) != CKR_OK) {
69699ebb4caSwyllys 		cred->cred = NULL;
69799ebb4caSwyllys 		cred->credlen = 0;
69899ebb4caSwyllys 	}
69999ebb4caSwyllys 
70099ebb4caSwyllys 	return (rv);
70199ebb4caSwyllys }
70299ebb4caSwyllys 
7032cbed729Swyllys #define	FILENAME_PROMPT gettext("Filename:")
7042cbed729Swyllys #define	FILENAME_MINLEN	1
7052cbed729Swyllys #define	FILENAME_MAXLEN MAXPATHLEN
70699ebb4caSwyllys 
7072cbed729Swyllys #define	COUNTRY_PROMPT	gettext("Country Name (2 letter code) [US]:")
7082cbed729Swyllys #define	STATE_PROMPT	gettext("State or Province Name (full name) " \
7092cbed729Swyllys 	"[Some-State]:")
7102cbed729Swyllys #define	LOCALITY_PROMPT	gettext("Locality Name (eg, city) []:")
7112cbed729Swyllys #define	ORG_PROMPT	gettext("Organization Name (eg, company) []:")
7122cbed729Swyllys #define	UNIT_PROMPT	gettext("Organizational Unit Name (eg, section) []:")
7132cbed729Swyllys #define	NAME_PROMPT	gettext("Common Name (eg, YOUR name) []:")
7142cbed729Swyllys #define	EMAIL_PROMPT	gettext("Email Address []:")
7152cbed729Swyllys 
7162cbed729Swyllys #define	SERNO_PROMPT	gettext("Serial Number (hex value, example: " \
7172cbed729Swyllys 	"0x01020304):")
7182cbed729Swyllys #define	SERNO_MINLEN	3
7192cbed729Swyllys #define	SERNO_MAXLEN	42
7202cbed729Swyllys 
7212cbed729Swyllys #define	LABEL_PROMPT	gettext("Enter a label for the certificate:")
7222cbed729Swyllys #define	LABEL_MINLEN	1
7232cbed729Swyllys #define	LABEL_MAXLEN	1024
72499ebb4caSwyllys 
72599ebb4caSwyllys #define	COUNTRY_DEFAULT "US"
7262cbed729Swyllys #define	STATE_DEFAULT	NULL
7272cbed729Swyllys #define	INVALID_INPUT 	gettext("Invalid input; please re-enter ...")
72899ebb4caSwyllys 
72999ebb4caSwyllys #define	SUBNAMESIZ	1024
73099ebb4caSwyllys #define	RDN_MIN		1
73199ebb4caSwyllys #define	RDN_MAX		64
73299ebb4caSwyllys #define	COUNTRYNAME_MIN	2
73399ebb4caSwyllys #define	COUNTRYNAME_MAX	2
73499ebb4caSwyllys 
73599ebb4caSwyllys static char *
73699ebb4caSwyllys get_input_string(char *prompt, char *default_str, int min_len, int max_len)
73799ebb4caSwyllys {
73899ebb4caSwyllys 	char buf[1024];
73999ebb4caSwyllys 	char *response = NULL;
74099ebb4caSwyllys 	char *ret = NULL;
74199ebb4caSwyllys 	int len;
74299ebb4caSwyllys 
74399ebb4caSwyllys 	for (;;) {
74499ebb4caSwyllys 		(void) printf("\t%s", prompt);
74599ebb4caSwyllys 		(void) fflush(stdout);
74699ebb4caSwyllys 
74799ebb4caSwyllys 		response = fgets(buf, sizeof (buf), stdin);
74899ebb4caSwyllys 		if (response == NULL) {
74999ebb4caSwyllys 			if (default_str != NULL) {
75099ebb4caSwyllys 				ret = strdup(default_str);
75199ebb4caSwyllys 			}
75299ebb4caSwyllys 			break;
75399ebb4caSwyllys 		}
75499ebb4caSwyllys 
75599ebb4caSwyllys 		/* Skip any leading white space. */
75699ebb4caSwyllys 		while (isspace(*response))
75799ebb4caSwyllys 			response++;
75899ebb4caSwyllys 		if (*response == '\0') {
75999ebb4caSwyllys 			if (default_str != NULL) {
76099ebb4caSwyllys 				ret = strdup(default_str);
76199ebb4caSwyllys 			}
76299ebb4caSwyllys 			break;
76399ebb4caSwyllys 		}
76499ebb4caSwyllys 
76599ebb4caSwyllys 		len = strlen(response);
76699ebb4caSwyllys 		response[len-1] = '\0'; /* get rid of "LF" */
76799ebb4caSwyllys 		len--;
76899ebb4caSwyllys 		if (len >= min_len && len <= max_len) {
76999ebb4caSwyllys 			ret = strdup(response);
77099ebb4caSwyllys 			break;
77199ebb4caSwyllys 		}
77299ebb4caSwyllys 
77399ebb4caSwyllys 		(void) printf("%s\n", INVALID_INPUT);
77499ebb4caSwyllys 
77599ebb4caSwyllys 	}
77699ebb4caSwyllys 
77799ebb4caSwyllys 	return (ret);
77899ebb4caSwyllys }
77999ebb4caSwyllys 
78099ebb4caSwyllys int
7812cbed729Swyllys get_filename(char *txt, char **result)
7822cbed729Swyllys {
7832cbed729Swyllys 	char prompt[1024];
7842cbed729Swyllys 	char *fname = NULL;
7852cbed729Swyllys 
7862cbed729Swyllys 	(void) snprintf(prompt, sizeof (prompt),
7872cbed729Swyllys 	    gettext("Enter filename for the %s: "),
7882cbed729Swyllys 	    txt);
7892cbed729Swyllys 	fname = get_input_string(prompt, NULL,
7902cbed729Swyllys 	    FILENAME_MINLEN, FILENAME_MAXLEN);
7912cbed729Swyllys 	*result = fname;
7922cbed729Swyllys 	return (0);
7932cbed729Swyllys }
7942cbed729Swyllys 
7952cbed729Swyllys int
7962cbed729Swyllys get_certlabel(char **result)
7972cbed729Swyllys {
7982cbed729Swyllys 	char *label = NULL;
7992cbed729Swyllys 
8002cbed729Swyllys 	label = get_input_string(LABEL_PROMPT, NULL,
8012cbed729Swyllys 	    LABEL_MINLEN, LABEL_MAXLEN);
8022cbed729Swyllys 	*result = label;
8032cbed729Swyllys 	return (0);
8042cbed729Swyllys }
8052cbed729Swyllys 
8062cbed729Swyllys int
8072cbed729Swyllys get_serial(char **result)
8082cbed729Swyllys {
8092cbed729Swyllys 	char *serial = NULL;
8102cbed729Swyllys 
8112cbed729Swyllys 	serial = get_input_string(SERNO_PROMPT, NULL, SERNO_MINLEN,
8122cbed729Swyllys 	    SERNO_MAXLEN);
8132cbed729Swyllys 
8142cbed729Swyllys 	*result = serial;
8152cbed729Swyllys 	return (0);
8162cbed729Swyllys }
8172cbed729Swyllys 
8182cbed729Swyllys int
81999ebb4caSwyllys get_subname(char **result)
82099ebb4caSwyllys {
82199ebb4caSwyllys 	char *country = NULL;
82299ebb4caSwyllys 	char *state = NULL;
82399ebb4caSwyllys 	char *locality = NULL;
82499ebb4caSwyllys 	char *org = NULL;
82599ebb4caSwyllys 	char *unit = NULL;
82699ebb4caSwyllys 	char *name = NULL;
82799ebb4caSwyllys 	char *email = NULL;
82899ebb4caSwyllys 	char *subname = NULL;
82999ebb4caSwyllys 
83099ebb4caSwyllys 	(void) printf("Entering following fields for subject (a DN) ...\n");
83199ebb4caSwyllys 	country = get_input_string(COUNTRY_PROMPT, COUNTRY_DEFAULT,
83299ebb4caSwyllys 	    COUNTRYNAME_MIN, COUNTRYNAME_MAX);
83399ebb4caSwyllys 	if (country == NULL)
83499ebb4caSwyllys 		return (-1);
83599ebb4caSwyllys 
83699ebb4caSwyllys 	state = get_input_string(STATE_PROMPT, STATE_DEFAULT,
83799ebb4caSwyllys 	    RDN_MIN, RDN_MAX);
83899ebb4caSwyllys 
83999ebb4caSwyllys 	locality = get_input_string(LOCALITY_PROMPT, NULL, RDN_MIN, RDN_MAX);
84099ebb4caSwyllys 	org = get_input_string(ORG_PROMPT, NULL, RDN_MIN, RDN_MAX);
84199ebb4caSwyllys 	unit = get_input_string(UNIT_PROMPT, NULL, RDN_MIN, RDN_MAX);
84299ebb4caSwyllys 	name = get_input_string(NAME_PROMPT, NULL, RDN_MIN, RDN_MAX);
84399ebb4caSwyllys 	email = get_input_string(EMAIL_PROMPT, NULL, RDN_MIN, RDN_MAX);
84499ebb4caSwyllys 
84599ebb4caSwyllys 	/* Now create a subject name from the input strings */
84699ebb4caSwyllys 	if ((subname = malloc(SUBNAMESIZ)) == NULL)
84799ebb4caSwyllys 		goto out;
84899ebb4caSwyllys 
84999ebb4caSwyllys 	(void) memset(subname, 0, SUBNAMESIZ);
85099ebb4caSwyllys 	(void) strlcpy(subname, "C=", SUBNAMESIZ);
85199ebb4caSwyllys 	(void) strlcat(subname, country, SUBNAMESIZ);
8522cbed729Swyllys 	if (state != NULL) {
8532cbed729Swyllys 		(void) strlcat(subname, ", ST=", SUBNAMESIZ);
85499ebb4caSwyllys 		(void) strlcat(subname, state, SUBNAMESIZ);
8552cbed729Swyllys 	}
85699ebb4caSwyllys 
8572cbed729Swyllys 	if (locality != NULL) {
8582cbed729Swyllys 		(void) strlcat(subname, ", L=", SUBNAMESIZ);
85999ebb4caSwyllys 		(void) strlcat(subname, locality, SUBNAMESIZ);
86099ebb4caSwyllys 	}
86199ebb4caSwyllys 
8622cbed729Swyllys 	if (org != NULL) {
8632cbed729Swyllys 		(void) strlcat(subname, ", O=", SUBNAMESIZ);
86499ebb4caSwyllys 		(void) strlcat(subname, org, SUBNAMESIZ);
86599ebb4caSwyllys 	}
86699ebb4caSwyllys 
8672cbed729Swyllys 	if (unit != NULL) {
8682cbed729Swyllys 		(void) strlcat(subname, ", OU=", SUBNAMESIZ);
86999ebb4caSwyllys 		(void) strlcat(subname, unit, SUBNAMESIZ);
87099ebb4caSwyllys 	}
87199ebb4caSwyllys 
8722cbed729Swyllys 	if (name != NULL) {
8732cbed729Swyllys 		(void) strlcat(subname, ", CN=", SUBNAMESIZ);
87499ebb4caSwyllys 		(void) strlcat(subname, name, SUBNAMESIZ);
87599ebb4caSwyllys 	}
87699ebb4caSwyllys 
8772cbed729Swyllys 	if (email != NULL) {
8782cbed729Swyllys 		(void) strlcat(subname, ", E=", SUBNAMESIZ);
87999ebb4caSwyllys 		(void) strlcat(subname, email, SUBNAMESIZ);
88099ebb4caSwyllys 	}
88199ebb4caSwyllys 
88299ebb4caSwyllys out:
88399ebb4caSwyllys 	if (country)
88499ebb4caSwyllys 		free(country);
88599ebb4caSwyllys 	if (state)
88699ebb4caSwyllys 		free(state);
88799ebb4caSwyllys 	if (locality)
88899ebb4caSwyllys 		free(locality);
88999ebb4caSwyllys 	if (org)
89099ebb4caSwyllys 		free(org);
89199ebb4caSwyllys 	if (unit)
89299ebb4caSwyllys 		free(unit);
89399ebb4caSwyllys 	if (name)
89499ebb4caSwyllys 		free(name);
89599ebb4caSwyllys 	if (email)
89699ebb4caSwyllys 		free(email);
89799ebb4caSwyllys 
89899ebb4caSwyllys 	if (subname == NULL)
89999ebb4caSwyllys 		return (-1);
90099ebb4caSwyllys 	else {
90199ebb4caSwyllys 		*result = subname;
90299ebb4caSwyllys 		return (0);
90399ebb4caSwyllys 	}
90499ebb4caSwyllys }
90599ebb4caSwyllys 
90699ebb4caSwyllys /*
90799ebb4caSwyllys  * Parse a string of KeyUsage values and convert
90899ebb4caSwyllys  * them to the correct KU Bits.
90999ebb4caSwyllys  * The field may be marked "critical" by prepending
91099ebb4caSwyllys  * "critical:" to the list.
91199ebb4caSwyllys  * EX:  critical:digitialSignature,keyEncipherment
91299ebb4caSwyllys  */
91399ebb4caSwyllys KMF_RETURN
91499ebb4caSwyllys verify_keyusage(char *kustr, uint16_t *kubits, int *critical)
91599ebb4caSwyllys {
91699ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
91799ebb4caSwyllys 	uint16_t kuval;
91899ebb4caSwyllys 	char *k;
91999ebb4caSwyllys 
92099ebb4caSwyllys 	*kubits = 0;
921d00756ccSwyllys 	if (kustr == NULL || strlen(kustr) == 0)
92299ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
92399ebb4caSwyllys 
92499ebb4caSwyllys 	/* Check to see if this is critical */
925d00756ccSwyllys 	if (strncasecmp(kustr, "critical:", strlen("critical:")) == 0) {
92699ebb4caSwyllys 		*critical = TRUE;
92799ebb4caSwyllys 		kustr += strlen("critical:");
92899ebb4caSwyllys 	} else {
92999ebb4caSwyllys 		*critical = FALSE;
93099ebb4caSwyllys 	}
93199ebb4caSwyllys 
93299ebb4caSwyllys 	k = strtok(kustr, ",");
93399ebb4caSwyllys 	while (k != NULL) {
93430a5e8faSwyllys 		kuval = kmf_string_to_ku(k);
93599ebb4caSwyllys 		if (kuval == 0) {
93699ebb4caSwyllys 			*kubits = 0;
93799ebb4caSwyllys 			return (KMF_ERR_BAD_PARAMETER);
93899ebb4caSwyllys 		}
93999ebb4caSwyllys 		*kubits |= kuval;
94099ebb4caSwyllys 		k = strtok(NULL, ",");
94199ebb4caSwyllys 	}
94299ebb4caSwyllys 
94399ebb4caSwyllys 	return (ret);
94499ebb4caSwyllys }
94599ebb4caSwyllys 
94699ebb4caSwyllys /*
94799ebb4caSwyllys  * Verify the alternate subject label is real or invalid.
94899ebb4caSwyllys  *
94999ebb4caSwyllys  * The field may be marked "critical" by prepending
95099ebb4caSwyllys  * "critical:" to the list.
95199ebb4caSwyllys  * EX:  "critical:IP=1.2.3.4"
95299ebb4caSwyllys  */
95399ebb4caSwyllys KMF_RETURN
95499ebb4caSwyllys verify_altname(char *arg, KMF_GENERALNAMECHOICES *type, int *critical)
95599ebb4caSwyllys {
95699ebb4caSwyllys 	char *p;
95799ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
95899ebb4caSwyllys 
95999ebb4caSwyllys 	/* Check to see if this is critical */
960d00756ccSwyllys 	if (strncasecmp(arg, "critical:", strlen("critical:")) == 0) {
96199ebb4caSwyllys 		*critical = TRUE;
96299ebb4caSwyllys 		arg += strlen("critical:");
96399ebb4caSwyllys 	} else {
96499ebb4caSwyllys 		*critical = FALSE;
96599ebb4caSwyllys 	}
96699ebb4caSwyllys 
96799ebb4caSwyllys 	/* Make sure there is an "=" sign */
96899ebb4caSwyllys 	p = strchr(arg, '=');
96999ebb4caSwyllys 	if (p == NULL)
97099ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
97199ebb4caSwyllys 
97299ebb4caSwyllys 	p[0] = '\0';
97399ebb4caSwyllys 
97499ebb4caSwyllys 	if (strcmp(arg, "IP") == 0)
97599ebb4caSwyllys 		*type = GENNAME_IPADDRESS;
97699ebb4caSwyllys 	else if (strcmp(arg, "DNS") == 0)
97799ebb4caSwyllys 		*type = GENNAME_DNSNAME;
97899ebb4caSwyllys 	else if (strcmp(arg, "EMAIL") == 0)
97999ebb4caSwyllys 		*type = GENNAME_RFC822NAME;
98099ebb4caSwyllys 	else if (strcmp(arg, "URI") == 0)
98199ebb4caSwyllys 		*type = GENNAME_URI;
98299ebb4caSwyllys 	else if (strcmp(arg, "DN") == 0)
98399ebb4caSwyllys 		*type = GENNAME_DIRECTORYNAME;
98499ebb4caSwyllys 	else if (strcmp(arg, "RID") == 0)
98599ebb4caSwyllys 		*type = GENNAME_REGISTEREDID;
986d00756ccSwyllys 	else if (strcmp(arg, "KRB") == 0)
987d00756ccSwyllys 		*type = GENNAME_KRB5PRINC;
988d00756ccSwyllys 	else if (strcmp(arg, "UPN") == 0)
989d00756ccSwyllys 		*type = GENNAME_SCLOGON_UPN;
99099ebb4caSwyllys 	else
99199ebb4caSwyllys 		rv = KMF_ERR_BAD_PARAMETER;
99299ebb4caSwyllys 
99399ebb4caSwyllys 	p[0] = '=';
99499ebb4caSwyllys 
99599ebb4caSwyllys 	return (rv);
99699ebb4caSwyllys }
99799ebb4caSwyllys 
99899ebb4caSwyllys int
99999ebb4caSwyllys get_token_password(KMF_KEYSTORE_TYPE kstype,
100099ebb4caSwyllys 	char *token_spec, KMF_CREDENTIAL *cred)
100199ebb4caSwyllys {
100299ebb4caSwyllys 	char	prompt[1024];
100372ca8cc9SWyllys Ingersoll 	char	temptoken[32];
100499ebb4caSwyllys 	char	*p = NULL;
100572ca8cc9SWyllys Ingersoll 	char	*t = NULL;
1006*47e946e7SWyllys Ingersoll 	int	len;
100799ebb4caSwyllys 
1008*47e946e7SWyllys Ingersoll 	(void) memset(temptoken, 0, sizeof (temptoken));
100999ebb4caSwyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
101099ebb4caSwyllys 		p = strchr(token_spec, ':');
101199ebb4caSwyllys 		if (p != NULL)
101299ebb4caSwyllys 			*p = 0;
101399ebb4caSwyllys 	}
1014*47e946e7SWyllys Ingersoll 	len = strlen(token_spec);
1015*47e946e7SWyllys Ingersoll 	if (len > sizeof (temptoken))
1016*47e946e7SWyllys Ingersoll 		len = sizeof (temptoken);
1017*47e946e7SWyllys Ingersoll 
1018*47e946e7SWyllys Ingersoll 	(void) strncpy(temptoken, token_spec, len);
101972ca8cc9SWyllys Ingersoll 
102072ca8cc9SWyllys Ingersoll 	/*
102172ca8cc9SWyllys Ingersoll 	 * Strip trailing whitespace
102272ca8cc9SWyllys Ingersoll 	 */
1023*47e946e7SWyllys Ingersoll 	t = temptoken + (len - 1);
102472ca8cc9SWyllys Ingersoll 	while (isspace(*t) && t >= temptoken) {
102572ca8cc9SWyllys Ingersoll 		*t = 0x00;
102672ca8cc9SWyllys Ingersoll 		t--;
102772ca8cc9SWyllys Ingersoll 	}
102872ca8cc9SWyllys Ingersoll 
102999ebb4caSwyllys 	/*
103099ebb4caSwyllys 	 * Login to the token first.
103199ebb4caSwyllys 	 */
103299ebb4caSwyllys 	(void) snprintf(prompt, sizeof (prompt),
103372ca8cc9SWyllys Ingersoll 	    gettext(DEFAULT_TOKEN_PROMPT), temptoken);
103499ebb4caSwyllys 
103599ebb4caSwyllys 	if (get_pin(prompt, NULL, (uchar_t **)&cred->cred,
103699ebb4caSwyllys 	    (ulong_t *)&cred->credlen) != CKR_OK) {
103799ebb4caSwyllys 		cred->cred = NULL;
103899ebb4caSwyllys 		cred->credlen = 0;
103999ebb4caSwyllys 	}
104099ebb4caSwyllys 
104199ebb4caSwyllys 	if (kstype == KMF_KEYSTORE_PK11TOKEN && p != NULL)
104299ebb4caSwyllys 		*p = ':';
104399ebb4caSwyllys 	return (KMF_OK);
104499ebb4caSwyllys }
104599ebb4caSwyllys 
104699ebb4caSwyllys KMF_RETURN
104799ebb4caSwyllys verify_file(char *filename)
104899ebb4caSwyllys {
104999ebb4caSwyllys 	KMF_RETURN ret = KMF_OK;
105099ebb4caSwyllys 	int fd;
105199ebb4caSwyllys 
105299ebb4caSwyllys 	/*
105399ebb4caSwyllys 	 * Attempt to open with  the EXCL flag so that if
105499ebb4caSwyllys 	 * it already exists, the open will fail.  It will
105599ebb4caSwyllys 	 * also fail if the file cannot be created due to
105699ebb4caSwyllys 	 * permissions on the parent directory, or if the
105799ebb4caSwyllys 	 * parent directory itself does not exist.
105899ebb4caSwyllys 	 */
105999ebb4caSwyllys 	fd = open(filename, O_CREAT | O_EXCL, 0600);
106099ebb4caSwyllys 	if (fd == -1)
106199ebb4caSwyllys 		return (KMF_ERR_OPEN_FILE);
106299ebb4caSwyllys 
106399ebb4caSwyllys 	/* If we were able to create it, delete it. */
106499ebb4caSwyllys 	(void) close(fd);
106599ebb4caSwyllys 	(void) unlink(filename);
106699ebb4caSwyllys 
106799ebb4caSwyllys 	return (ret);
106899ebb4caSwyllys }
106999ebb4caSwyllys 
107099ebb4caSwyllys void
107199ebb4caSwyllys display_error(void *handle, KMF_RETURN errcode, char *prefix)
107299ebb4caSwyllys {
107399ebb4caSwyllys 	KMF_RETURN rv1, rv2;
107499ebb4caSwyllys 	char *plugin_errmsg = NULL;
107599ebb4caSwyllys 	char *kmf_errmsg = NULL;
107699ebb4caSwyllys 
107730a5e8faSwyllys 	rv1 = kmf_get_plugin_error_str(handle, &plugin_errmsg);
107830a5e8faSwyllys 	rv2 = kmf_get_kmf_error_str(errcode, &kmf_errmsg);
107999ebb4caSwyllys 
108099ebb4caSwyllys 	cryptoerror(LOG_STDERR, "%s:", prefix);
108199ebb4caSwyllys 	if (rv1 == KMF_OK && plugin_errmsg) {
108230a5e8faSwyllys 		cryptoerror(LOG_STDERR, gettext("keystore error: %s"),
108399ebb4caSwyllys 		    plugin_errmsg);
108430a5e8faSwyllys 		kmf_free_str(plugin_errmsg);
108599ebb4caSwyllys 	}
108699ebb4caSwyllys 
108799ebb4caSwyllys 	if (rv2 == KMF_OK && kmf_errmsg) {
108830a5e8faSwyllys 		cryptoerror(LOG_STDERR, gettext("libkmf error: %s"),
108999ebb4caSwyllys 		    kmf_errmsg);
109030a5e8faSwyllys 		kmf_free_str(kmf_errmsg);
109199ebb4caSwyllys 	}
109299ebb4caSwyllys 
109399ebb4caSwyllys 	if (rv1 != KMF_OK && rv2 != KMF_OK)
109499ebb4caSwyllys 		cryptoerror(LOG_STDERR, gettext("<unknown error>\n"));
109599ebb4caSwyllys 
109699ebb4caSwyllys }
1097d00756ccSwyllys 
1098d00756ccSwyllys static KMF_RETURN
1099d00756ccSwyllys addToEKUList(EKU_LIST *ekus, int critical, KMF_OID *newoid)
1100d00756ccSwyllys {
1101d00756ccSwyllys 	if (newoid != NULL && ekus != NULL) {
1102d00756ccSwyllys 		ekus->eku_count++;
1103d00756ccSwyllys 
1104d00756ccSwyllys 		ekus->critlist = realloc(ekus->critlist,
1105d00756ccSwyllys 		    ekus->eku_count * sizeof (int));
1106d00756ccSwyllys 		if (ekus->critlist != NULL)
1107d00756ccSwyllys 			ekus->critlist[ekus->eku_count-1] = critical;
1108d00756ccSwyllys 		else
1109d00756ccSwyllys 			return (KMF_ERR_MEMORY);
1110d00756ccSwyllys 
1111d00756ccSwyllys 		ekus->ekulist = realloc(
1112d00756ccSwyllys 		    ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
1113d00756ccSwyllys 		if (ekus->ekulist != NULL)
1114d00756ccSwyllys 			ekus->ekulist[ekus->eku_count-1] = *newoid;
1115d00756ccSwyllys 		else
1116d00756ccSwyllys 			return (KMF_ERR_MEMORY);
1117d00756ccSwyllys 	}
1118d00756ccSwyllys 	return (KMF_OK);
1119d00756ccSwyllys }
1120d00756ccSwyllys 
1121d00756ccSwyllys void
1122d00756ccSwyllys free_eku_list(EKU_LIST *ekus)
1123d00756ccSwyllys {
1124d00756ccSwyllys 	if (ekus != NULL && ekus->eku_count > 0) {
1125d00756ccSwyllys 		int i;
1126d00756ccSwyllys 		for (i = 0; i < ekus->eku_count; i++) {
1127d00756ccSwyllys 			kmf_free_data(&ekus->ekulist[i]);
1128d00756ccSwyllys 		}
1129d00756ccSwyllys 		free(ekus->ekulist);
1130d00756ccSwyllys 		free(ekus->critlist);
1131d00756ccSwyllys 	}
1132d00756ccSwyllys }
1133d00756ccSwyllys 
1134d00756ccSwyllys static KMF_RETURN
1135d00756ccSwyllys parse_ekus(char *ekustr, EKU_LIST *ekus)
1136d00756ccSwyllys {
1137d00756ccSwyllys 	KMF_RETURN rv = KMF_OK;
1138d00756ccSwyllys 	KMF_OID *newoid;
1139d00756ccSwyllys 	int critical;
1140d00756ccSwyllys 
1141d00756ccSwyllys 	if (strncasecmp(ekustr, "critical:",
1142d00756ccSwyllys 	    strlen("critical:")) == 0) {
1143d00756ccSwyllys 		critical = TRUE;
1144d00756ccSwyllys 		ekustr += strlen("critical:");
1145d00756ccSwyllys 	} else {
1146d00756ccSwyllys 		critical = FALSE;
1147d00756ccSwyllys 	}
1148d00756ccSwyllys 	newoid = kmf_ekuname_to_oid(ekustr);
1149d00756ccSwyllys 	if (newoid != NULL) {
1150d00756ccSwyllys 		rv = addToEKUList(ekus, critical, newoid);
1151d00756ccSwyllys 		free(newoid);
1152d00756ccSwyllys 	} else {
1153d00756ccSwyllys 		rv = PK_ERR_USAGE;
1154d00756ccSwyllys 	}
1155d00756ccSwyllys 
1156d00756ccSwyllys 	return (rv);
1157d00756ccSwyllys }
1158d00756ccSwyllys 
1159d00756ccSwyllys KMF_RETURN
1160d00756ccSwyllys verify_ekunames(char *ekuliststr, EKU_LIST **ekulist)
1161d00756ccSwyllys {
1162d00756ccSwyllys 	KMF_RETURN rv = KMF_OK;
1163d00756ccSwyllys 	char *p;
1164d00756ccSwyllys 	EKU_LIST *ekus = NULL;
1165d00756ccSwyllys 
1166d00756ccSwyllys 	if (ekuliststr == NULL || strlen(ekuliststr) == 0)
1167d00756ccSwyllys 		return (0);
1168d00756ccSwyllys 
1169d00756ccSwyllys 	/*
1170d00756ccSwyllys 	 * The list should be comma separated list of EKU Names.
1171d00756ccSwyllys 	 */
1172d00756ccSwyllys 	p = strtok(ekuliststr, ",");
1173d00756ccSwyllys 
1174d00756ccSwyllys 	/* If no tokens found, then maybe it's just a single EKU value */
1175d00756ccSwyllys 	if (p == NULL) {
1176d00756ccSwyllys 		rv = parse_ekus(ekuliststr, ekus);
1177d00756ccSwyllys 	}
1178d00756ccSwyllys 
1179d00756ccSwyllys 	while (p != NULL) {
1180d00756ccSwyllys 		rv = parse_ekus(p, ekus);
1181d00756ccSwyllys 
1182d00756ccSwyllys 		if (rv != KMF_OK)
1183d00756ccSwyllys 			break;
1184d00756ccSwyllys 		p = strtok(NULL, ",");
1185d00756ccSwyllys 	}
1186d00756ccSwyllys 
1187d00756ccSwyllys 	if (rv != KMF_OK)
1188d00756ccSwyllys 		free_eku_list(ekus);
1189d00756ccSwyllys 	else
1190d00756ccSwyllys 		*ekulist = ekus;
1191d00756ccSwyllys 
1192d00756ccSwyllys 	return (rv);
1193d00756ccSwyllys }
1194fa60c371Swyllys 
1195fa60c371Swyllys KMF_RETURN
1196fa60c371Swyllys token_auth_needed(KMF_HANDLE_T handle, char *tokenlabel, int *auth)
1197fa60c371Swyllys {
1198fa60c371Swyllys 	CK_TOKEN_INFO info;
1199fa60c371Swyllys 	CK_SLOT_ID slot;
1200fa60c371Swyllys 	CK_RV ckrv;
1201fa60c371Swyllys 	KMF_RETURN rv;
1202fa60c371Swyllys 
1203fa60c371Swyllys 	*auth = 0;
1204fa60c371Swyllys 	rv = kmf_pk11_token_lookup(handle, tokenlabel, &slot);
1205fa60c371Swyllys 	if (rv != KMF_OK)
1206fa60c371Swyllys 		return (rv);
1207fa60c371Swyllys 
1208fa60c371Swyllys 	ckrv = C_GetTokenInfo(slot, &info);
1209fa60c371Swyllys 	if (ckrv != KMF_OK)
1210fa60c371Swyllys 		return (KMF_ERR_INTERNAL);
1211fa60c371Swyllys 
1212fa60c371Swyllys 	*auth = (info.flags & CKF_LOGIN_REQUIRED);
1213fa60c371Swyllys 
1214fa60c371Swyllys 	return (KMF_OK);
1215fa60c371Swyllys }
1216