17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
599ebb4cwyllys * Common Development and Distribution License (the "License").
699ebb4cwyllys * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
202c9a247Wyllys Ingersoll *
212c9a247Wyllys Ingersoll * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
227c478bdstevel@tonic-gate */
237c478bdstevel@tonic-gate
247c478bdstevel@tonic-gate/*
257c478bdstevel@tonic-gate * This file contains the functions that are shared among
267c478bdstevel@tonic-gate * the various services this tool will ultimately provide.
277711facdinak * The functions in this file return PKCS#11 CK_RV errors.
287711facdinak * Only one session and one login per token is supported
297711facdinak * at this time.
307c478bdstevel@tonic-gate */
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#include <stdio.h>
337c478bdstevel@tonic-gate#include <stdlib.h>
347c478bdstevel@tonic-gate#include <string.h>
357c478bdstevel@tonic-gate#include <ctype.h>
3699ebb4cwyllys#include <sys/types.h>
3799ebb4cwyllys#include <sys/stat.h>
3899ebb4cwyllys#include <fcntl.h>
3999ebb4cwyllys#include <tzfile.h>
407c478bdstevel@tonic-gate#include <cryptoutil.h>
417c478bdstevel@tonic-gate#include <security/cryptoki.h>
4299ebb4cwyllys#include <kmfapi.h>
437c478bdstevel@tonic-gate
4499ebb4cwyllys#include "common.h"
457711facdinak
467711facdinak/* Local status variables. */
477711facdinakstatic boolean_t	initialized = B_FALSE;
487711facdinakstatic boolean_t	session_opened = B_FALSE;
497711facdinakstatic boolean_t	logged_in = B_FALSE;
507c478bdstevel@tonic-gate
5149e2129dinak/* Supporting structures and global variables for getopt_av(). */
5249e2129dinaktypedef struct	av_opts_s {
5349e2129dinak	int		shortnm;	/* short name character */
5449e2129dinak	char		*longnm;	/* long name string, NOT terminated */
5549e2129dinak	int		longnm_len;	/* length of long name string */
5649e2129dinak	boolean_t	has_arg;	/* takes optional argument */
5749e2129dinak} av_opts;
5849e2129dinakstatic av_opts		*opts_av = NULL;
5949e2129dinakstatic const char	*_save_optstr = NULL;
6049e2129dinakstatic int		_save_numopts = 0;
6149e2129dinak
6249e2129dinakint			optind_av = 1;
6349e2129dinakchar			*optarg_av = NULL;
6449e2129dinak
6599ebb4cwyllysstatic void close_sess(CK_SESSION_HANDLE);
6699ebb4cwyllysstatic void logout_token(CK_SESSION_HANDLE);
6799ebb4cwyllys
68e65e5c2Wyllys Ingersollstruct oid_table_entry {
69e65e5c2Wyllys Ingersoll	const KMF_OID *oid;
70e65e5c2Wyllys Ingersoll	char *name;
71e65e5c2Wyllys Ingersoll};
72e65e5c2Wyllys Ingersoll
73e65e5c2Wyllys Ingersollstruct oid_table_entry oid_table[] = {
74e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp112r1, "secp112r1"},
75e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp112r2, "secp112r2"},
76e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp128r1, "secp128r1"},
77e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp128r2, "secp128r2"},
78e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp160k1, "secp160k1"},
79e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp160r1, "secp160r1"},
80e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp160r2, "secp160r2"},
81e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp192k1, "secp192k1"},
82e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp192r1, "secp192r1"},
83e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp224k1, "secp224k1"},
84e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp224r1, "secp224r1"},
85e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp256k1, "secp256k1"},
86e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp256r1, "secp256r1"},
87e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp384r1, "secp384r1"},
88e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_secp521r1, "secp521r1"},
89e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect113r1, "sect113r1"},
90e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect113r2, "sect113r2"},
91e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect131r1, "sect131r1"},
92e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect131r2, "sect131r2"},
93e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect163k1, "sect163k1"},
94e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect163r1, "sect163r1"},
95e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect163r2, "sect163r2"},
96e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect193r1, "sect193r1"},
97e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect193r2, "sect193r2"},
98e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect233k1, "sect233k1"},
99e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect233r1, "sect233r1"},
100e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect239k1, "sect239k1"},
101e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect283k1, "sect283k1"},
102e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect283r1, "sect283r1"},
103e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect409k1, "sect409k1"},
104e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect409r1, "sect409r1"},
105e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect571k1, "sect571k1"},
106e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_sect571r1, "sect571r1"},
107e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb163v1, "c2pnb163v1"},
108e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb163v2, "c2pnb163v2"},
109e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb163v3, "c2pnb163v3"},
110e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb176v1, "c2pnb176v1"},
111e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb191v1, "c2tnb191v1"},
112e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb191v2, "c2tnb191v2"},
113e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb191v3, "c2tnb191v3"},
114e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb208w1, "c2pnb208w1"},
115e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb239v1, "c2tnb239v1"},
116e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb239v2, "c2tnb239v2"},
117e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb239v3, "c2tnb239v3"},
118e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb272w1, "c2pnb272w1"},
119e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb304w1, "c2pnb304w1"},
120e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb359v1, "c2tnb359v1"},
121e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2pnb368w1, "c2pnb368w1"},
122e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_c2tnb431r1, "c2tnb431r1"},
123e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_prime192v2, "prime192v2"},
124e65e5c2Wyllys Ingersoll	{ &KMFOID_ECC_prime192v3, "prime192v3"},
125e65e5c2Wyllys Ingersoll	{ &KMFOID_MD5, "md5"},
126e65e5c2Wyllys Ingersoll	{ &KMFOID_SHA1, "sha1"},
127e65e5c2Wyllys Ingersoll	{ &KMFOID_SHA256, "sha256"},
128e65e5c2Wyllys Ingersoll	{ &KMFOID_SHA384, "sha384"},
129e65e5c2Wyllys Ingersoll	{ &KMFOID_SHA512, "sha512"}
130e65e5c2Wyllys Ingersoll};
131e65e5c2Wyllys Ingersollint number_of_oids = sizeof (oid_table) / sizeof (struct oid_table_entry);
132e65e5c2Wyllys Ingersoll#define	number_of_curves (number_of_oids - 5)
133e65e5c2Wyllys Ingersoll
1347c478bdstevel@tonic-gate/*
1357711facdinak * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
1367711facdinak * along with setting/resetting state variables.
1377c478bdstevel@tonic-gate */
138448b861wyllysstatic CK_RV
139448b861wyllysinit_pkcs11(void)
1407c478bdstevel@tonic-gate{
1417711facdinak	CK_RV		rv = CKR_OK;
1427711facdinak
1437711facdinak	/* If C_Initialize() already called, nothing to do here. */
1447711facdinak	if (initialized == B_TRUE)
1457711facdinak		return (CKR_OK);
1467c478bdstevel@tonic-gate
1477711facdinak	/* Reset state variables because C_Initialize() not yet done. */
1487711facdinak	session_opened = B_FALSE;
1497711facdinak	logged_in = B_FALSE;
1507c478bdstevel@tonic-gate
1517711facdinak	/* Initialize PKCS#11 library. */
1527711facdinak	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
1537711facdinak	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
1547711facdinak		return (rv);
1557711facdinak	}
1567c478bdstevel@tonic-gate
1577711facdinak	initialized = B_TRUE;
1587711facdinak	return (CKR_OK);
1597c478bdstevel@tonic-gate}
1607c478bdstevel@tonic-gate
1617c478bdstevel@tonic-gate/*
1627711facdinak * Finalize PKCS#11 library and reset state variables.  Open sessions,
1637711facdinak * if any, are closed, and thereby any logins are logged out also.
1647c478bdstevel@tonic-gate */
1657711facdinakvoid
1667711facdinakfinal_pk11(CK_SESSION_HANDLE sess)
1677c478bdstevel@tonic-gate{
1687c478bdstevel@tonic-gate
1697711facdinak	/* If the library wasn't initialized, nothing to do here. */
1707711facdinak	if (!initialized)
1717711facdinak		return;
1727c478bdstevel@tonic-gate
1737711facdinak	/* Make sure the sesion is closed first. */
1747711facdinak	close_sess(sess);
1757711facdinak
1767711facdinak	(void) C_Finalize(NULL);
1777711facdinak	initialized = B_FALSE;
1787711facdinak}
1797711facdinak
1807711facdinak/*
1817711facdinak * Close PKCS#11 session and reset state variables.  Any logins are
1827711facdinak * logged out.
1837711facdinak */
18499ebb4cwyllysstatic void
1857711facdinakclose_sess(CK_SESSION_HANDLE sess)
1867711facdinak{
1877711facdinak
1886f2b04aToomas Soome	if (sess == 0) {
1897711facdinak		return;
1907711facdinak	}
1917711facdinak
1927711facdinak	/* If session is already closed, nothing to do here. */
1937711facdinak	if (!session_opened)
1947711facdinak		return;
1957711facdinak
1967711facdinak	/* Make sure user is logged out of token. */
1977711facdinak	logout_token(sess);
1987711facdinak
1997711facdinak	(void) C_CloseSession(sess);
2007711facdinak	session_opened = B_FALSE;
2017711facdinak}
2027711facdinak
2037711facdinak/*
2047711facdinak * Log user out of token and reset status variable.
2057711facdinak */
20699ebb4cwyllysstatic void
2077711facdinaklogout_token(CK_SESSION_HANDLE sess)
2087711facdinak{
2097711facdinak
2106f2b04aToomas Soome	if (sess == 0) {
2117711facdinak		return;
2127c478bdstevel@tonic-gate	}
2137c478bdstevel@tonic-gate
2147711facdinak	/* If already logged out, nothing to do here. */
2157711facdinak	if (!logged_in)
2167711facdinak		return;
2177711facdinak
2187711facdinak	(void) C_Logout(sess);
2197711facdinak	logged_in = B_FALSE;
2207711facdinak}
2217711facdinak
2227711facdinak/*
2237711facdinak * Gets PIN from user.  Caller needs to free the returned PIN when done.
2247711facdinak * If two prompts are given, the PIN is confirmed with second prompt.
2257711facdinak * Note that getphassphrase() may return data in static memory area.
2267711facdinak */
2277711facdinakCK_RV
2287711facdinakget_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
2297711facdinak{
230d00756cwyllys	char *save_phrase, *phrase1, *phrase2;
2317711facdinak
2327711facdinak	/* Prompt user for a PIN. */
2337711facdinak	if (prompt1 == NULL) {
2347711facdinak		return (CKR_ARGUMENTS_BAD);
2357711facdinak	}
2367711facdinak	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
2377711facdinak		return (CKR_FUNCTION_FAILED);
2387711facdinak	}
2397711facdinak
2407711facdinak	/* Duplicate 1st PIN in separate chunk of memory. */
2417711facdinak	if ((save_phrase = strdup(phrase1)) == NULL)
2427711facdinak		return (CKR_HOST_MEMORY);
2437711facdinak
2447711facdinak	/* If second prompt given, PIN confirmation is requested. */
2457711facdinak	if (prompt2 != NULL) {
2467711facdinak		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
2477711facdinak			free(save_phrase);
2487711facdinak			return (CKR_FUNCTION_FAILED);
2497711facdinak		}
2507711facdinak		if (strcmp(save_phrase, phrase2) != 0) {
2517711facdinak			free(save_phrase);
2527711facdinak			return (CKR_PIN_INCORRECT);
2537711facdinak		}
2547711facdinak	}
2557711facdinak
2567711facdinak	*pin = (CK_UTF8CHAR_PTR)save_phrase;
2577711facdinak	*pinlen = strlen(save_phrase);
2587711facdinak	return (CKR_OK);
2597711facdinak}
2607711facdinak
261d00756cwyllysint
262d00756cwyllysyn_to_int(char *ynstr)
263d00756cwyllys{
264d00756cwyllys	char *y = gettext("yes");
265d00756cwyllys	char *n = gettext("no");
266d00756cwyllys	if (ynstr == NULL)
267d00756cwyllys		return (-1);
268d00756cwyllys
269d00756cwyllys	if (strncasecmp(ynstr, y, 1) == 0)
270d00756cwyllys		return (1);
271d00756cwyllys	else if (strncasecmp(ynstr, n, 1) == 0)
272d00756cwyllys		return (0);
273d00756cwyllys	else
274d00756cwyllys		return (-1);
275d00756cwyllys}
276d00756cwyllys
2777711facdinak/*
2787711facdinak * Gets yes/no response from user.  If either no prompt is supplied, a
2797711facdinak * default prompt is used.  If not message for invalid input is supplied,
2807711facdinak * a default will not be provided.  If the user provides no response,
2817711facdinak * the input default B_TRUE == yes, B_FALSE == no is returned.
2827711facdinak * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
2837711facdinak */
2847711facdinakboolean_t
2857711facdinakyesno(char *prompt, char *invalid, boolean_t dflt)
2867711facdinak{
287d00756cwyllys	char	*response, buf[1024];
288d00756cwyllys	int	ans;
2897711facdinak
2907711facdinak	if (prompt == NULL)
2917711facdinak		prompt = gettext("Enter (y)es or (n)o? ");
2927711facdinak
2937711facdinak	for (;;) {
2947711facdinak		/* Prompt user. */
2957711facdinak		(void) printf("%s", prompt);
2967711facdinak		(void) fflush(stdout);
2977711facdinak
2987711facdinak		/* Get the response. */
2997711facdinak		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
3007711facdinak			break;		/* go to default response */
3017711facdinak
3027711facdinak		/* Skip any leading white space. */
3037711facdinak		while (isspace(*response))
3047711facdinak			response++;
3057711facdinak		if (*response == '\0')
3067711facdinak			break;		/* go to default response */
3077711facdinak
308d00756cwyllys		ans = yn_to_int(response);
309d00756cwyllys		if (ans == 1)
3107711facdinak			return (B_TRUE);
311d00756cwyllys		else if (ans == 0)
3127711facdinak			return (B_FALSE);
3137711facdinak
3147711facdinak		/* Indicate invalid input, and try again. */
3157711facdinak		if (invalid != NULL)
31630a5e8fwyllys			(void) printf("%s", invalid);
3177711facdinak	}
3187711facdinak	return (dflt);
3197711facdinak}
3207711facdinak
3217711facdinak/*
3227711facdinak * Gets the list of slots which have tokens in them.  Keeps adjusting
3237711facdinak * the size of the slot list buffer until the call is successful or an
3247711facdinak * irrecoverable error occurs.
3257711facdinak */
3267711facdinakCK_RV
3277711facdinakget_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
3287711facdinak{
3297711facdinak	CK_ULONG	tmp_count = 0;
3307711facdinak	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
3317711facdinak	int		rv = CKR_OK;
3327711facdinak
3337711facdinak	if (!initialized)
334448b861wyllys		if ((rv = init_pkcs11()) != CKR_OK)
3357711facdinak			return (rv);
3367711facdinak
3377711facdinak	/*
3387711facdinak	 * Get the slot count first because we don't know how many
3397711facdinak	 * slots there are and how many of those slots even have tokens.
3407711facdinak	 * Don't specify an arbitrary buffer size for the slot list;
3417711facdinak	 * it may be too small (see section 11.5 of PKCS#11 spec).
3427711facdinak	 * Also select only those slots that have tokens in them,
3437711facdinak	 * because this tool has no need to know about empty slots.
3447711facdinak	 */
3457711facdinak	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
3467711facdinak		return (rv);
3477711facdinak
3487711facdinak	if (tmp_count == 0) {
3497711facdinak		*slot_list = NULL_PTR;
3507711facdinak		*slot_count = 0;
3517711facdinak		return (CKR_OK);
3527711facdinak	}
3537711facdinak
3547711facdinak	/* Allocate initial space for the slot list. */
3557711facdinak	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
3567711facdinak	    sizeof (CK_SLOT_ID))) == NULL)
3577711facdinak		return (CKR_HOST_MEMORY);
3587711facdinak
3597711facdinak	/* Then get the slot list itself. */
3607711facdinak	for (;;) {
3617711facdinak		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
3627711facdinak			*slot_list = tmp_list;
3637711facdinak			*slot_count = tmp_count;
3647711facdinak			break;
3657711facdinak		}
3667711facdinak
3677711facdinak		if (rv != CKR_BUFFER_TOO_SMALL) {
3687711facdinak			free(tmp_list);
3697711facdinak			break;
3707711facdinak		}
3717711facdinak
3727711facdinak		/* If the number of slots grew, try again. */
3737711facdinak		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
3747711facdinak		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
3757711facdinak			free(tmp_list);
3767711facdinak			rv = CKR_HOST_MEMORY;
3777711facdinak			break;
3787711facdinak		}
3797711facdinak		tmp_list = tmp2_list;
3807711facdinak	}
3817711facdinak
3827711facdinak	return (rv);
3837c478bdstevel@tonic-gate}
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate/*
38699ebb4cwyllys * Breaks out the getopt-style option string into a structure that can be
38799ebb4cwyllys * traversed later for calls to getopt_av().  Option string is NOT altered,
38899ebb4cwyllys * but the struct fields point to locations within option string.
3897c478bdstevel@tonic-gate */
3907c478bdstevel@tonic-gatestatic int
39199ebb4cwyllyspopulate_opts(char *optstring)
3927c478bdstevel@tonic-gate{
39399ebb4cwyllys	int		i;
39499ebb4cwyllys	av_opts		*temp;
3957c478bdstevel@tonic-gate	char		*marker;
3967c478bdstevel@tonic-gate
39799ebb4cwyllys	if (optstring == NULL || *optstring == '\0')
39899ebb4cwyllys		return (0);
39999ebb4cwyllys
40099ebb4cwyllys	/*
40199ebb4cwyllys	 * This tries to imitate getopt(3c) Each option must conform to:
40299ebb4cwyllys	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
40399ebb4cwyllys	 * If long name is missing, the short name is used for long name.
40499ebb4cwyllys	 */
40599ebb4cwyllys	for (i = 0; *optstring != '\0'; i++) {
40699ebb4cwyllys		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
40799ebb4cwyllys		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
40899ebb4cwyllys			if (opts_av != NULL)
40999ebb4cwyllys				free(opts_av);
41099ebb4cwyllys			opts_av = NULL;
41199ebb4cwyllys			return (0);
41299ebb4cwyllys		} else {
41399ebb4cwyllys			opts_av = (av_opts *)temp;
41499ebb4cwyllys		}
4157c478bdstevel@tonic-gate
41699ebb4cwyllys		(void) memset(&opts_av[i], 0, sizeof (av_opts));
41799ebb4cwyllys		marker = optstring;		/* may need optstring later */
4187c478bdstevel@tonic-gate
41999ebb4cwyllys		opts_av[i].shortnm = *marker++;	/* set short name */
42099ebb4cwyllys
42199ebb4cwyllys		if (*marker == ':') {		/* check for opt arg */
42299ebb4cwyllys			marker++;
42399ebb4cwyllys			opts_av[i].has_arg = B_TRUE;
42499ebb4cwyllys		}
42599ebb4cwyllys
42699ebb4cwyllys		if (*marker == '(') {		/* check and set long name */
42799ebb4cwyllys			marker++;
42899ebb4cwyllys			opts_av[i].longnm = marker;
42999ebb4cwyllys			opts_av[i].longnm_len = strcspn(marker, ")");
43099ebb4cwyllys			optstring = marker + opts_av[i].longnm_len + 1;
43199ebb4cwyllys		} else {
43299ebb4cwyllys			/* use short name option character */
43399ebb4cwyllys			opts_av[i].longnm = optstring;
43499ebb4cwyllys			opts_av[i].longnm_len = 1;
43599ebb4cwyllys			optstring = marker;
43699ebb4cwyllys		}
43799ebb4cwyllys	}
43899ebb4cwyllys
43999ebb4cwyllys	return (i);
4407c478bdstevel@tonic-gate}
4417c478bdstevel@tonic-gate
4427c478bdstevel@tonic-gate/*
44399ebb4cwyllys * getopt_av() is very similar to getopt(3c) in that the takes an option
44499ebb4cwyllys * string, compares command line arguments for matches, and returns a single
44599ebb4cwyllys * letter option when a match is found.  However, getopt_av() differs from
44699ebb4cwyllys * getopt(3c) by requiring that only longname options and values be found
44799ebb4cwyllys * on the command line and all leading dashes are omitted.  In other words,
44899ebb4cwyllys * it tries to enforce only longname "option=value" arguments on the command
44999ebb4cwyllys * line.  Boolean options are not allowed either.
4507c478bdstevel@tonic-gate */
45199ebb4cwyllysint
45299ebb4cwyllysgetopt_av(int argc, char * const *argv, const char *optstring)
4537c478bdstevel@tonic-gate{
45499ebb4cwyllys	int	i;
45599ebb4cwyllys	int	len;
45699ebb4cwyllys	char   *cur_option;
4577c478bdstevel@tonic-gate
45899ebb4cwyllys	if (optind_av >= argc)
45999ebb4cwyllys		return (EOF);
4607c478bdstevel@tonic-gate
46199ebb4cwyllys	/* First time or when optstring changes from previous one */
46299ebb4cwyllys	if (_save_optstr != optstring) {
46399ebb4cwyllys		if (opts_av != NULL)
46430a5e8fwyllys			free(opts_av);
46599ebb4cwyllys		opts_av = NULL;
46699ebb4cwyllys		_save_optstr = optstring;
46799ebb4cwyllys		_save_numopts = populate_opts((char *)optstring);
46899ebb4cwyllys	}
4697c478bdstevel@tonic-gate
47099ebb4cwyllys	for (i = 0; i < _save_numopts; i++) {
47199ebb4cwyllys		cur_option = argv[optind_av];
4727c478bdstevel@tonic-gate
47399ebb4cwyllys		if (strcmp(cur_option, "--") == 0) {
47499ebb4cwyllys			optind_av++;
47599ebb4cwyllys			break;
4767c478bdstevel@tonic-gate		}
4777c478bdstevel@tonic-gate
47899ebb4cwyllys		if (cur_option[0] == '-' && strlen(cur_option) == 2) {
47999ebb4cwyllys			len = 1;
48099ebb4cwyllys			cur_option++; /* remove "-" */
48199ebb4cwyllys		} else {
48299ebb4cwyllys			len = strcspn(cur_option, "=");
48399ebb4cwyllys		}
4847c478bdstevel@tonic-gate
48599ebb4cwyllys		if (len == opts_av[i].longnm_len && strncmp(cur_option,
48699ebb4cwyllys		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
48799ebb4cwyllys			/* matched */
48899ebb4cwyllys			if (!opts_av[i].has_arg) {
48999ebb4cwyllys				optind_av++;
49099ebb4cwyllys				return (opts_av[i].shortnm);
49199ebb4cwyllys			}
49299ebb4cwyllys
49399ebb4cwyllys			/* needs optarg */
49499ebb4cwyllys			if (cur_option[len] == '=') {
49599ebb4cwyllys				optarg_av = &(cur_option[len+1]);
49699ebb4cwyllys				optind_av++;
49799ebb4cwyllys				return (opts_av[i].shortnm);
49899ebb4cwyllys			}
49999ebb4cwyllys
50099ebb4cwyllys			optarg_av = NULL;
50199ebb4cwyllys			optind_av++;
50299ebb4cwyllys			return ((int)'?');
50399ebb4cwyllys		}
5047c478bdstevel@tonic-gate	}
5057c478bdstevel@tonic-gate
50699ebb4cwyllys	return (EOF);
5077c478bdstevel@tonic-gate}
5087c478bdstevel@tonic-gate
50999ebb4cwyllysKMF_KEYSTORE_TYPE
51099ebb4cwyllysKS2Int(char *keystore_str)
51149e2129dinak{
51299ebb4cwyllys	if (keystore_str == NULL)
51399ebb4cwyllys		return (0);
514d00756cwyllys	if (strcasecmp(keystore_str, "pkcs11") == 0)
51599ebb4cwyllys		return (KMF_KEYSTORE_PK11TOKEN);
516d00756cwyllys	else if (strcasecmp(keystore_str, "nss") == 0)
51799ebb4cwyllys		return (KMF_KEYSTORE_NSS);
518d00756cwyllys	else if (strcasecmp(keystore_str, "file") == 0)
51999ebb4cwyllys		return (KMF_KEYSTORE_OPENSSL);
52099ebb4cwyllys	else
52199ebb4cwyllys		return (0);
52299ebb4cwyllys}
52349e2129dinak
524e65e5c2Wyllys Ingersoll/*
525e65e5c2Wyllys Ingersoll * compare_oids
526e65e5c2Wyllys Ingersoll * return 1 if equal
527e65e5c2Wyllys Ingersoll */
528e65e5c2Wyllys Ingersollboolean_t
529e65e5c2Wyllys Ingersollcompare_oids(KMF_OID *oid1, const KMF_OID *oid2)
530e65e5c2Wyllys Ingersoll{
531e65e5c2Wyllys Ingersoll	return ((oid1->Length == oid2->Length) &&
532e65e5c2Wyllys Ingersoll	    !memcmp(oid1->Data, oid2->Data, oid1->Length));
533e65e5c2Wyllys Ingersoll}
53449e2129dinak
53599ebb4cwyllysint
536e65e5c2Wyllys IngersollStr2KeyType(char *algm, KMF_OID *hashoid, KMF_KEY_ALG *ktype,
537e65e5c2Wyllys Ingersoll    KMF_ALGORITHM_INDEX *sigAlg)
53899ebb4cwyllys{
53999ebb4cwyllys	if (algm == NULL) {
540e65e5c2Wyllys Ingersoll		/* Default to SHA1+RSA */
5414165f46Wyllys Ingersoll		*sigAlg = KMF_ALGID_SHA1WithRSA;
54299ebb4cwyllys		*ktype = KMF_RSA;
54399ebb4cwyllys	} else if (strcasecmp(algm, "DSA") == 0) {
544e65e5c2Wyllys Ingersoll		if (hashoid == NULL ||
545e65e5c2Wyllys Ingersoll		    compare_oids(hashoid, &KMFOID_SHA1))
546e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA1WithDSA;
547e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA256))
548e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA256WithDSA;
549e65e5c2Wyllys Ingersoll		else
550e65e5c2Wyllys Ingersoll			return (-1); /* unsupported hash/key combo */
55199ebb4cwyllys		*ktype = KMF_DSA;
55299ebb4cwyllys	} else if (strcasecmp(algm, "RSA") == 0) {
553e65e5c2Wyllys Ingersoll		if (hashoid == NULL ||
554e65e5c2Wyllys Ingersoll		    compare_oids(hashoid, &KMFOID_SHA1))
555e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA1WithRSA;
556e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA256))
557e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA256WithRSA;
558e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA384))
559e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA384WithRSA;
560e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA512))
561e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA512WithRSA;
562e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_MD5))
563e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_MD5WithRSA;
564e65e5c2Wyllys Ingersoll		else
565e65e5c2Wyllys Ingersoll			return (-1); /* unsupported hash/key combo */
56699ebb4cwyllys		*ktype = KMF_RSA;
567e65e5c2Wyllys Ingersoll	} else if (strcasecmp(algm, "EC") == 0) {
568e65e5c2Wyllys Ingersoll		/* EC keys may be used with some SHA2 hashes */
569e65e5c2Wyllys Ingersoll		if (hashoid == NULL ||
570e65e5c2Wyllys Ingersoll		    compare_oids(hashoid, &KMFOID_SHA1))
571e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA1WithECDSA;
572e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA256))
573e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA256WithECDSA;
574e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA384))
575e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA384WithECDSA;
576e65e5c2Wyllys Ingersoll		else if (compare_oids(hashoid, &KMFOID_SHA512))
577e65e5c2Wyllys Ingersoll			*sigAlg = KMF_ALGID_SHA512WithECDSA;
578e65e5c2Wyllys Ingersoll		else
579e65e5c2Wyllys Ingersoll			return (-1); /* unsupported hash/key combo */
580e65e5c2Wyllys Ingersoll
581e65e5c2Wyllys Ingersoll		*ktype = KMF_ECDSA;
58299ebb4cwyllys	} else {
58399ebb4cwyllys		return (-1);
58449e2129dinak	}
58599ebb4cwyllys	return (0);
58649e2129dinak}
58749e2129dinak
58899ebb4cwyllysint
58999ebb4cwyllysStr2SymKeyType(char *algm, KMF_KEY_ALG *ktype)
59049e2129dinak{
59199ebb4cwyllys	if (algm == NULL)
59299ebb4cwyllys		*ktype = KMF_AES;
59399ebb4cwyllys	else if (strcasecmp(algm, "aes") == 0)
59499ebb4cwyllys		*ktype = KMF_AES;
59599ebb4cwyllys	else if (strcasecmp(algm, "arcfour") == 0)
59699ebb4cwyllys		*ktype = KMF_RC4;
59799ebb4cwyllys	else if (strcasecmp(algm, "des") == 0)
59899ebb4cwyllys		*ktype = KMF_DES;
59999ebb4cwyllys	else if (strcasecmp(algm, "3des") == 0)
60099ebb4cwyllys		*ktype = KMF_DES3;
601c197cb9hylee	else if (strcasecmp(algm, "generic") == 0)
602c197cb9hylee		*ktype = KMF_GENERIC_SECRET;
60399ebb4cwyllys	else
60499ebb4cwyllys		return (-1);
60549e2129dinak
60699ebb4cwyllys	return (0);
60749e2129dinak}
60849e2129dinak
60949e2129dinakint
61099ebb4cwyllysStr2Lifetime(char *ltimestr, uint32_t *ltime)
61149e2129dinak{
61299ebb4cwyllys	int num;
61399ebb4cwyllys	char timetok[6];
61449e2129dinak
615d00756cwyllys	if (ltimestr == NULL || strlen(ltimestr) == 0) {
61699ebb4cwyllys		/* default to 1 year lifetime */
61799ebb4cwyllys		*ltime = SECSPERDAY * DAYSPERNYEAR;
61899ebb4cwyllys		return (0);
61949e2129dinak	}
62049e2129dinak
62199ebb4cwyllys	(void) memset(timetok, 0, sizeof (timetok));
62299ebb4cwyllys	if (sscanf(ltimestr, "%d-%06s", &num, timetok) != 2)
62399ebb4cwyllys		return (-1);
62449e2129dinak
625d00756cwyllys	if (strcasecmp(timetok, "day") == 0||
626d00756cwyllys	    strcasecmp(timetok, "days") == 0) {
62799ebb4cwyllys		*ltime = num * SECSPERDAY;
628d00756cwyllys	} else if (strcasecmp(timetok, "hour") == 0||
629d00756cwyllys	    strcasecmp(timetok, "hours") == 0) {
63099ebb4cwyllys		*ltime = num * SECSPERHOUR;
631d00756cwyllys	} else if (strcasecmp(timetok, "year") == 0 ||
632d00756cwyllys	    strcasecmp(timetok, "years") == 0) {
63399ebb4cwyllys		*ltime = num * SECSPERDAY * DAYSPERNYEAR;
63499ebb4cwyllys	} else {
63599ebb4cwyllys		*ltime = 0;
63649e2129dinak		return (-1);
63749e2129dinak	}
63849e2129dinak
63999ebb4cwyllys	return (0);
64099ebb4cwyllys}
64149e2129dinak
64299ebb4cwyllysint
64399ebb4cwyllysOT2Int(char *objclass)
64499ebb4cwyllys{
64599ebb4cwyllys	char *c = NULL;
64699ebb4cwyllys	int retval = 0;
64749e2129dinak
64899ebb4cwyllys	if (objclass == NULL)
64999ebb4cwyllys		return (-1);
65049e2129dinak
65199ebb4cwyllys	c = strchr(objclass, ':');
65299ebb4cwyllys	if (c != NULL) {
653d00756cwyllys		if (strcasecmp(c, ":private") == 0)
65499ebb4cwyllys			retval = PK_PRIVATE_OBJ;
655d00756cwyllys		else if (strcasecmp(c, ":public") == 0)
65699ebb4cwyllys			retval = PK_PUBLIC_OBJ;
657d00756cwyllys		else if (strcasecmp(c, ":both") == 0)
65899ebb4cwyllys			retval = PK_PRIVATE_OBJ | PK_PUBLIC_OBJ;
65999ebb4cwyllys		else /* unrecognized option */
66099ebb4cwyllys			return (-1);
66199ebb4cwyllys
66299ebb4cwyllys		*c = '\0';
66399ebb4cwyllys	}
66499ebb4cwyllys
665d00756cwyllys	if (strcasecmp(objclass, "public") == 0) {
66699ebb4cwyllys		if (retval)
66799ebb4cwyllys			return (-1);
66830a5e8fwyllys		return (retval | PK_PUBLIC_OBJ | PK_CERT_OBJ | PK_PUBKEY_OBJ);
669d00756cwyllys	} else if (strcasecmp(objclass, "private") == 0) {
67099ebb4cwyllys		if (retval)
67199ebb4cwyllys			return (-1);
67299ebb4cwyllys		return (retval | PK_PRIKEY_OBJ | PK_PRIVATE_OBJ);
673d00756cwyllys	} else if (strcasecmp(objclass, "both") == 0) {
67499ebb4cwyllys		if (retval)
67599ebb4cwyllys			return (-1);
67699ebb4cwyllys		return (PK_KEY_OBJ | PK_PUBLIC_OBJ | PK_PRIVATE_OBJ);
677d00756cwyllys	} else if (strcasecmp(objclass, "cert") == 0) {
67899ebb4cwyllys		return (retval | PK_CERT_OBJ);
679d00756cwyllys	} else if (strcasecmp(objclass, "key") == 0) {
68099ebb4cwyllys		if (retval == 0) /* return all keys */
68199ebb4cwyllys			return (retval | PK_KEY_OBJ);
68299ebb4cwyllys		else if (retval == (PK_PRIVATE_OBJ | PK_PUBLIC_OBJ))
68399ebb4cwyllys			/* return all keys */
68499ebb4cwyllys			return (retval | PK_KEY_OBJ);
68599ebb4cwyllys		else if (retval & PK_PUBLIC_OBJ)
68699ebb4cwyllys			/* Only return public keys */
68799ebb4cwyllys			return (retval | PK_PUBKEY_OBJ);
68899ebb4cwyllys		else if (retval & PK_PRIVATE_OBJ)
68999ebb4cwyllys			/* Only return private keys */
69099ebb4cwyllys			return (retval | PK_PRIKEY_OBJ);
691d00756cwyllys	} else if (strcasecmp(objclass, "crl") == 0) {
69299ebb4cwyllys		if (retval)
69399ebb4cwyllys			return (-1);
69499ebb4cwyllys		return (retval | PK_CRL_OBJ);
69599ebb4cwyllys	}
69699ebb4cwyllys
69799ebb4cwyllys	if (retval == 0) /* No matches found */
69899ebb4cwyllys		retval = -1;
69999ebb4cwyllys	return (retval);
70049e2129dinak}
70149e2129dinak
70299ebb4cwyllysKMF_ENCODE_FORMAT
70399ebb4cwyllysStr2Format(char *formstr)
7047c478bdstevel@tonic-gate{
705d00756cwyllys	if (formstr == NULL || strcasecmp(formstr, "der") == 0)
70699ebb4cwyllys		return (KMF_FORMAT_ASN1);
707d00756cwyllys	if (strcasecmp(formstr, "pem") == 0)
70899ebb4cwyllys		return (KMF_FORMAT_PEM);
709d00756cwyllys	if (strcasecmp(formstr, "pkcs12") == 0)
71099ebb4cwyllys		return (KMF_FORMAT_PKCS12);
711d00756cwyllys	if (strcasecmp(formstr, "raw") == 0)
71230a5e8fwyllys		return (KMF_FORMAT_RAWKEY);
71399ebb4cwyllys
71499ebb4cwyllys	return (KMF_FORMAT_UNDEF);
71599ebb4cwyllys}
7167c478bdstevel@tonic-gate
71799ebb4cwyllysKMF_RETURN
718d00756cwyllysselect_token(void *kmfhandle, char *token, int readonly)
71999ebb4c