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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*7711facfSdinak  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * This file contains the functions that are shared among
317c478bd9Sstevel@tonic-gate  * the various services this tool will ultimately provide.
32*7711facfSdinak  * The functions in this file return PKCS#11 CK_RV errors.
33*7711facfSdinak  * Only one session and one login per token is supported
34*7711facfSdinak  * at this time.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <stdio.h>
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <string.h>
407c478bd9Sstevel@tonic-gate #include <ctype.h>
417c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
427c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
437c478bd9Sstevel@tonic-gate #include "common.h"
44*7711facfSdinak #include "biginteger.h"
457c478bd9Sstevel@tonic-gate 
46*7711facfSdinak /* True and false for attribute templates. */
47*7711facfSdinak CK_BBOOL	pk_true = B_TRUE;
48*7711facfSdinak CK_BBOOL	pk_false = B_FALSE;
49*7711facfSdinak 
50*7711facfSdinak /* Local status variables. */
51*7711facfSdinak static boolean_t	initialized = B_FALSE;
52*7711facfSdinak static boolean_t	session_opened = B_FALSE;
53*7711facfSdinak static boolean_t	session_writable = B_FALSE;
54*7711facfSdinak static boolean_t	logged_in = B_FALSE;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
57*7711facfSdinak  * Perform PKCS#11 setup here.  Currently only C_Initialize is required,
58*7711facfSdinak  * along with setting/resetting state variables.
597c478bd9Sstevel@tonic-gate  */
60*7711facfSdinak CK_RV
61*7711facfSdinak init_pk11(void)
627c478bd9Sstevel@tonic-gate {
63*7711facfSdinak 	CK_RV		rv = CKR_OK;
64*7711facfSdinak 
65*7711facfSdinak 	cryptodebug("inside init_pk11");
66*7711facfSdinak 
67*7711facfSdinak 	/* If C_Initialize() already called, nothing to do here. */
68*7711facfSdinak 	if (initialized == B_TRUE)
69*7711facfSdinak 		return (CKR_OK);
707c478bd9Sstevel@tonic-gate 
71*7711facfSdinak 	/* Reset state variables because C_Initialize() not yet done. */
72*7711facfSdinak 	session_opened = B_FALSE;
73*7711facfSdinak 	session_writable = B_FALSE;
74*7711facfSdinak 	logged_in = B_FALSE;
757c478bd9Sstevel@tonic-gate 
76*7711facfSdinak 	/* Initialize PKCS#11 library. */
77*7711facfSdinak 	cryptodebug("calling C_Initialize()");
78*7711facfSdinak 	if ((rv = C_Initialize(NULL_PTR)) != CKR_OK &&
79*7711facfSdinak 	    rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
80*7711facfSdinak 		return (rv);
81*7711facfSdinak 	}
827c478bd9Sstevel@tonic-gate 
83*7711facfSdinak 	initialized = B_TRUE;
84*7711facfSdinak 	return (CKR_OK);
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
88*7711facfSdinak  * Finalize PKCS#11 library and reset state variables.  Open sessions,
89*7711facfSdinak  * if any, are closed, and thereby any logins are logged out also.
907c478bd9Sstevel@tonic-gate  */
91*7711facfSdinak void
92*7711facfSdinak final_pk11(CK_SESSION_HANDLE sess)
937c478bd9Sstevel@tonic-gate {
94*7711facfSdinak 	cryptodebug("inside final_pk11");
957c478bd9Sstevel@tonic-gate 
96*7711facfSdinak 	/* If the library wasn't initialized, nothing to do here. */
97*7711facfSdinak 	if (!initialized)
98*7711facfSdinak 		return;
997c478bd9Sstevel@tonic-gate 
100*7711facfSdinak 	/* Make sure the sesion is closed first. */
101*7711facfSdinak 	close_sess(sess);
102*7711facfSdinak 
103*7711facfSdinak 	cryptodebug("calling C_Finalize()");
104*7711facfSdinak 	(void) C_Finalize(NULL);
105*7711facfSdinak 	initialized = B_FALSE;
106*7711facfSdinak }
107*7711facfSdinak 
108*7711facfSdinak /*
109*7711facfSdinak  * Create a PKCS#11 session on the given slot, and set state information.
110*7711facfSdinak  * If session is already open, check that the read-only/read-write state
111*7711facfSdinak  * requested matches that of the session.  If it doesn't, make it so.
112*7711facfSdinak  */
113*7711facfSdinak CK_RV
114*7711facfSdinak open_sess(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_SESSION_HANDLE_PTR sess)
115*7711facfSdinak {
116*7711facfSdinak 	CK_RV		rv = CKR_OK;
117*7711facfSdinak 
118*7711facfSdinak 	cryptodebug("inside open_sess");
119*7711facfSdinak 
120*7711facfSdinak 	/* If the session is already open, check the session flags. */
121*7711facfSdinak 	if (session_opened) {
122*7711facfSdinak 		/*
123*7711facfSdinak 		 * If requesting R/W session and it is currently R/O,
124*7711facfSdinak 		 * need to close the session and reopen it R/W.  The
125*7711facfSdinak 		 * other cases are considered acceptable:
126*7711facfSdinak 		 *	sess_flags		current state
127*7711facfSdinak 		 *	----------		-------------
128*7711facfSdinak 		 *	~CKF_RW_SESSION		!session_writable
129*7711facfSdinak 		 *	~CKF_RW_SESSION		session_writable
130*7711facfSdinak 		 *	CKF_RW_SESSION		session_writable
131*7711facfSdinak 		 */
132*7711facfSdinak 		if ((sess_flags & CKF_RW_SESSION) && !session_writable)
133*7711facfSdinak 			close_sess(*sess);
134*7711facfSdinak 		else
135*7711facfSdinak 			return (CKR_OK);
136*7711facfSdinak 	}
137*7711facfSdinak 
138*7711facfSdinak 	/* Make sure the PKCS#11 is already initialized. */
139*7711facfSdinak 	if (!initialized)
140*7711facfSdinak 		if ((rv = init_pk11()) != CKR_OK)
141*7711facfSdinak 			return (rv);
142*7711facfSdinak 
143*7711facfSdinak 	/* Create a session for subsequent operations. */
144*7711facfSdinak 	cryptodebug("calling C_OpenSession()");
145*7711facfSdinak 	if ((rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION|sess_flags,
146*7711facfSdinak 	    NULL, NULL, sess)) != CKR_OK)
147*7711facfSdinak 		return (rv);
148*7711facfSdinak 	session_opened = B_TRUE;
149*7711facfSdinak 	session_writable = (sess_flags & CKF_RW_SESSION) ? B_TRUE : B_FALSE;
150*7711facfSdinak 	return (CKR_OK);
151*7711facfSdinak }
152*7711facfSdinak 
153*7711facfSdinak /*
154*7711facfSdinak  * Close PKCS#11 session and reset state variables.  Any logins are
155*7711facfSdinak  * logged out.
156*7711facfSdinak  */
157*7711facfSdinak void
158*7711facfSdinak close_sess(CK_SESSION_HANDLE sess)
159*7711facfSdinak {
160*7711facfSdinak 	cryptodebug("inside close_sess");
161*7711facfSdinak 
162*7711facfSdinak 	if (sess == NULL) {
163*7711facfSdinak 		cryptodebug("session handle is null");
164*7711facfSdinak 		return;
165*7711facfSdinak 	}
166*7711facfSdinak 
167*7711facfSdinak 	/* If session is already closed, nothing to do here. */
168*7711facfSdinak 	session_writable = B_FALSE;
169*7711facfSdinak 	if (!session_opened)
170*7711facfSdinak 		return;
171*7711facfSdinak 
172*7711facfSdinak 	/* Make sure user is logged out of token. */
173*7711facfSdinak 	logout_token(sess);
174*7711facfSdinak 
175*7711facfSdinak 	cryptodebug("calling C_CloseSession()");
176*7711facfSdinak 	(void) C_CloseSession(sess);
177*7711facfSdinak 	session_opened = B_FALSE;
178*7711facfSdinak }
179*7711facfSdinak 
180*7711facfSdinak /*
181*7711facfSdinak  * Log user into token in given slot.  If this first login ever for this
182*7711facfSdinak  * token, the initial PIN is "changeme", C_Login() will succeed, but all
183*7711facfSdinak  * PKCS#11 calls following the C_Login() will fail with CKR_PIN_EXPIRED.
184*7711facfSdinak  */
185*7711facfSdinak CK_RV
186*7711facfSdinak login_token(CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG pinlen,
187*7711facfSdinak 	    CK_SESSION_HANDLE_PTR sess)
188*7711facfSdinak {
189*7711facfSdinak 	CK_RV		rv = CKR_OK;
190*7711facfSdinak 
191*7711facfSdinak 	cryptodebug("inside login_token");
192*7711facfSdinak 
193*7711facfSdinak 	/* If already logged in, nothing to do here. */
194*7711facfSdinak 	if (logged_in)
195*7711facfSdinak 		return (CKR_OK);
196*7711facfSdinak 
197*7711facfSdinak 	/* Make sure we have a session first, assume R/O is enough. */
198*7711facfSdinak 	if (!session_opened)
199*7711facfSdinak 		if ((rv = open_sess(slot_id, CKF_SERIAL_SESSION, sess)) !=
200*7711facfSdinak 		    CKR_OK)
201*7711facfSdinak 			return (rv);
202*7711facfSdinak 
203*7711facfSdinak 	/* Log the user into the token. */
204*7711facfSdinak 	cryptodebug("calling C_Login()");
205*7711facfSdinak 	if ((rv = C_Login(*sess, CKU_USER, pin, pinlen)) != CKR_OK) {
206*7711facfSdinak 		cryptodebug("C_Login returns %s", pkcs11_strerror(rv));
207*7711facfSdinak 		return (rv);
208*7711facfSdinak 	}
209*7711facfSdinak 
210*7711facfSdinak 	logged_in = B_TRUE;
211*7711facfSdinak 	return (CKR_OK);
212*7711facfSdinak }
213*7711facfSdinak 
214*7711facfSdinak /*
215*7711facfSdinak  * Log user out of token and reset status variable.
216*7711facfSdinak  */
217*7711facfSdinak void
218*7711facfSdinak logout_token(CK_SESSION_HANDLE sess)
219*7711facfSdinak {
220*7711facfSdinak 	cryptodebug("inside logout_token");
221*7711facfSdinak 
222*7711facfSdinak 	if (sess == NULL) {
223*7711facfSdinak 		cryptodebug("session handle is null");
224*7711facfSdinak 		return;
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
227*7711facfSdinak 	/* If already logged out, nothing to do here. */
228*7711facfSdinak 	if (!logged_in)
229*7711facfSdinak 		return;
230*7711facfSdinak 
231*7711facfSdinak 	cryptodebug("calling C_Logout()");
232*7711facfSdinak 	(void) C_Logout(sess);
233*7711facfSdinak 	logged_in = B_FALSE;
234*7711facfSdinak }
235*7711facfSdinak 
236*7711facfSdinak /*
237*7711facfSdinak  * Shortcut function to get from an uninitialized state to user logged in.
238*7711facfSdinak  * If the library is already initialized, the session is already opened,
239*7711facfSdinak  * or the user is already logged in, those steps are skipped and the next
240*7711facfSdinak  * step is checked.
241*7711facfSdinak  */
242*7711facfSdinak CK_RV
243*7711facfSdinak quick_start(CK_SLOT_ID slot_id, CK_FLAGS sess_flags, CK_UTF8CHAR_PTR pin,
244*7711facfSdinak 	    CK_ULONG pinlen, CK_SESSION_HANDLE_PTR sess)
245*7711facfSdinak {
246*7711facfSdinak 	CK_RV		rv = CKR_OK;
247*7711facfSdinak 
248*7711facfSdinak 	cryptodebug("inside quick_start");
249*7711facfSdinak 
250*7711facfSdinak 	/* Call open_sess() explicitly if R/W session is needed. */
251*7711facfSdinak 	if (sess_flags & CKF_RW_SESSION)
252*7711facfSdinak 		if ((rv = open_sess(slot_id, sess_flags, sess)) != CKR_OK)
253*7711facfSdinak 			return (rv);
254*7711facfSdinak 
255*7711facfSdinak 	if ((rv = login_token(slot_id, pin, pinlen, sess)) != CKR_OK)
256*7711facfSdinak 		return (rv);
257*7711facfSdinak 
258*7711facfSdinak 	return (CKR_OK);
259*7711facfSdinak }
260*7711facfSdinak 
261*7711facfSdinak /*
262*7711facfSdinak  * Shortcut function to go from any state to uninitialized PKCS#11 library.
263*7711facfSdinak  */
264*7711facfSdinak void
265*7711facfSdinak quick_finish(CK_SESSION_HANDLE sess)
266*7711facfSdinak {
267*7711facfSdinak 	cryptodebug("inside quick_finish");
268*7711facfSdinak 
269*7711facfSdinak 	/* All the needed calls are done implicitly. */
270*7711facfSdinak 	final_pk11(sess);
271*7711facfSdinak }
272*7711facfSdinak 
273*7711facfSdinak /*
274*7711facfSdinak  * Gets PIN from user.  Caller needs to free the returned PIN when done.
275*7711facfSdinak  * If two prompts are given, the PIN is confirmed with second prompt.
276*7711facfSdinak  * Note that getphassphrase() may return data in static memory area.
277*7711facfSdinak  */
278*7711facfSdinak CK_RV
279*7711facfSdinak get_pin(char *prompt1, char *prompt2, CK_UTF8CHAR_PTR *pin, CK_ULONG *pinlen)
280*7711facfSdinak {
281*7711facfSdinak 	char		*save_phrase, *phrase1, *phrase2;
282*7711facfSdinak 
283*7711facfSdinak 	cryptodebug("inside get_pin");
284*7711facfSdinak 
285*7711facfSdinak 	/* Prompt user for a PIN. */
286*7711facfSdinak 	if (prompt1 == NULL) {
287*7711facfSdinak 		cryptodebug("no passphrase prompt given");
288*7711facfSdinak 		return (CKR_ARGUMENTS_BAD);
289*7711facfSdinak 	}
290*7711facfSdinak 	if ((phrase1 = getpassphrase(prompt1)) == NULL) {
291*7711facfSdinak 		cryptodebug("getpassphrase() failed");
292*7711facfSdinak 		return (CKR_FUNCTION_FAILED);
293*7711facfSdinak 	}
294*7711facfSdinak 
295*7711facfSdinak 	/* Duplicate 1st PIN in separate chunk of memory. */
296*7711facfSdinak 	if ((save_phrase = strdup(phrase1)) == NULL)
297*7711facfSdinak 		return (CKR_HOST_MEMORY);
298*7711facfSdinak 
299*7711facfSdinak 	/* If second prompt given, PIN confirmation is requested. */
300*7711facfSdinak 	if (prompt2 != NULL) {
301*7711facfSdinak 		if ((phrase2 = getpassphrase(prompt2)) == NULL) {
302*7711facfSdinak 			cryptodebug("getpassphrase() confirmation failed");
303*7711facfSdinak 			free(save_phrase);
304*7711facfSdinak 			return (CKR_FUNCTION_FAILED);
305*7711facfSdinak 		}
306*7711facfSdinak 		if (strcmp(save_phrase, phrase2) != 0) {
307*7711facfSdinak 			cryptodebug("passphrases do not match");
308*7711facfSdinak 			free(save_phrase);
309*7711facfSdinak 			return (CKR_PIN_INCORRECT);
310*7711facfSdinak 		}
311*7711facfSdinak 	}
312*7711facfSdinak 
313*7711facfSdinak 	*pin = (CK_UTF8CHAR_PTR)save_phrase;
314*7711facfSdinak 	*pinlen = strlen(save_phrase);
315*7711facfSdinak 	return (CKR_OK);
316*7711facfSdinak }
317*7711facfSdinak 
318*7711facfSdinak /*
319*7711facfSdinak  * Gets yes/no response from user.  If either no prompt is supplied, a
320*7711facfSdinak  * default prompt is used.  If not message for invalid input is supplied,
321*7711facfSdinak  * a default will not be provided.  If the user provides no response,
322*7711facfSdinak  * the input default B_TRUE == yes, B_FALSE == no is returned.
323*7711facfSdinak  * Otherwise, B_TRUE is returned for yes, and B_FALSE for no.
324*7711facfSdinak  */
325*7711facfSdinak boolean_t
326*7711facfSdinak yesno(char *prompt, char *invalid, boolean_t dflt)
327*7711facfSdinak {
328*7711facfSdinak 	char		*response, buf[1024];
329*7711facfSdinak 	char		*yes = gettext("yes");
330*7711facfSdinak 	char		*no = gettext("no");
331*7711facfSdinak 
332*7711facfSdinak 	cryptodebug("inside yesno");
333*7711facfSdinak 
334*7711facfSdinak 	if (prompt == NULL)
335*7711facfSdinak 		prompt = gettext("Enter (y)es or (n)o? ");
336*7711facfSdinak 
337*7711facfSdinak 	for (;;) {
338*7711facfSdinak 		/* Prompt user. */
339*7711facfSdinak 		(void) printf("%s", prompt);
340*7711facfSdinak 		(void) fflush(stdout);
341*7711facfSdinak 
342*7711facfSdinak 		/* Get the response. */
343*7711facfSdinak 		if ((response = fgets(buf, sizeof (buf), stdin)) == NULL)
344*7711facfSdinak 			break;		/* go to default response */
345*7711facfSdinak 
346*7711facfSdinak 		/* Skip any leading white space. */
347*7711facfSdinak 		while (isspace(*response))
348*7711facfSdinak 			response++;
349*7711facfSdinak 		if (*response == '\0')
350*7711facfSdinak 			break;		/* go to default response */
351*7711facfSdinak 
352*7711facfSdinak 		/* Is it valid input?  Return appropriately. */
353*7711facfSdinak 		if (strncasecmp(response, yes, 1) == 0)
354*7711facfSdinak 			return (B_TRUE);
355*7711facfSdinak 		if (strncasecmp(response, no, 1) == 0)
356*7711facfSdinak 			return (B_FALSE);
357*7711facfSdinak 
358*7711facfSdinak 		/* Indicate invalid input, and try again. */
359*7711facfSdinak 		if (invalid != NULL)
360*7711facfSdinak 		    (void) printf("%s", invalid);
361*7711facfSdinak 	}
362*7711facfSdinak 	return (dflt);
363*7711facfSdinak }
364*7711facfSdinak 
365*7711facfSdinak /*
366*7711facfSdinak  * Gets the list of slots which have tokens in them.  Keeps adjusting
367*7711facfSdinak  * the size of the slot list buffer until the call is successful or an
368*7711facfSdinak  * irrecoverable error occurs.
369*7711facfSdinak  */
370*7711facfSdinak CK_RV
371*7711facfSdinak get_token_slots(CK_SLOT_ID_PTR *slot_list, CK_ULONG *slot_count)
372*7711facfSdinak {
373*7711facfSdinak 	CK_ULONG	tmp_count = 0;
374*7711facfSdinak 	CK_SLOT_ID_PTR	tmp_list = NULL_PTR, tmp2_list = NULL_PTR;
375*7711facfSdinak 	int		rv = CKR_OK;
376*7711facfSdinak 
377*7711facfSdinak 	cryptodebug("inside get_token_slots");
378*7711facfSdinak 
379*7711facfSdinak 	if (!initialized)
380*7711facfSdinak 		if ((rv = init_pk11()) != CKR_OK)
381*7711facfSdinak 			return (rv);
382*7711facfSdinak 
383*7711facfSdinak 	/*
384*7711facfSdinak 	 * Get the slot count first because we don't know how many
385*7711facfSdinak 	 * slots there are and how many of those slots even have tokens.
386*7711facfSdinak 	 * Don't specify an arbitrary buffer size for the slot list;
387*7711facfSdinak 	 * it may be too small (see section 11.5 of PKCS#11 spec).
388*7711facfSdinak 	 * Also select only those slots that have tokens in them,
389*7711facfSdinak 	 * because this tool has no need to know about empty slots.
390*7711facfSdinak 	 */
391*7711facfSdinak 	cryptodebug("calling C_GetSlotList() for slot count");
392*7711facfSdinak 	if ((rv = C_GetSlotList(1, NULL_PTR, &tmp_count)) != CKR_OK)
393*7711facfSdinak 		return (rv);
394*7711facfSdinak 
395*7711facfSdinak 	if (tmp_count == 0) {
396*7711facfSdinak 		cryptodebug("no slots with tokens found");
397*7711facfSdinak 		*slot_list = NULL_PTR;
398*7711facfSdinak 		*slot_count = 0;
399*7711facfSdinak 		return (CKR_OK);
400*7711facfSdinak 	}
401*7711facfSdinak 
402*7711facfSdinak 	/* Allocate initial space for the slot list. */
403*7711facfSdinak 	if ((tmp_list = (CK_SLOT_ID_PTR) malloc(tmp_count *
404*7711facfSdinak 	    sizeof (CK_SLOT_ID))) == NULL)
405*7711facfSdinak 		return (CKR_HOST_MEMORY);
406*7711facfSdinak 
407*7711facfSdinak 	/* Then get the slot list itself. */
408*7711facfSdinak 	for (;;) {
409*7711facfSdinak 		cryptodebug("calling C_GetSlotList()");
410*7711facfSdinak 		if ((rv = C_GetSlotList(1, tmp_list, &tmp_count)) == CKR_OK) {
411*7711facfSdinak 			*slot_list = tmp_list;
412*7711facfSdinak 			*slot_count = tmp_count;
413*7711facfSdinak 			break;
414*7711facfSdinak 		}
415*7711facfSdinak 
416*7711facfSdinak 		if (rv != CKR_BUFFER_TOO_SMALL) {
417*7711facfSdinak 			free(tmp_list);
418*7711facfSdinak 			break;
419*7711facfSdinak 		}
420*7711facfSdinak 
421*7711facfSdinak 		/* If the number of slots grew, try again. */
422*7711facfSdinak 		cryptodebug("number of tokens present increased");
423*7711facfSdinak 		if ((tmp2_list = (CK_SLOT_ID_PTR) realloc(tmp_list,
424*7711facfSdinak 		    tmp_count * sizeof (CK_SLOT_ID))) == NULL) {
425*7711facfSdinak 			free(tmp_list);
426*7711facfSdinak 			rv = CKR_HOST_MEMORY;
427*7711facfSdinak 			break;
428*7711facfSdinak 		}
429*7711facfSdinak 		tmp_list = tmp2_list;
430*7711facfSdinak 	}
431*7711facfSdinak 
432*7711facfSdinak 	return (rv);
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate /*
4367c478bd9Sstevel@tonic-gate  * memcmp_pad_max() is a specialized version of memcmp() which
4377c478bd9Sstevel@tonic-gate  * compares two pieces of data up to a maximum length.  If the
4387c478bd9Sstevel@tonic-gate  * the two data match up the maximum length, they are considered
4397c478bd9Sstevel@tonic-gate  * matching.  Trailing blanks do not cause the match to fail if
4407c478bd9Sstevel@tonic-gate  * one of the data is shorted.
4417c478bd9Sstevel@tonic-gate  *
4427c478bd9Sstevel@tonic-gate  * Examples of matches:
4437c478bd9Sstevel@tonic-gate  *	"one"           |
4447c478bd9Sstevel@tonic-gate  *	"one      "     |
4457c478bd9Sstevel@tonic-gate  *	                ^maximum length
4467c478bd9Sstevel@tonic-gate  *
4477c478bd9Sstevel@tonic-gate  *	"Number One     |  X"	(X is beyond maximum length)
4487c478bd9Sstevel@tonic-gate  *	"Number One   " |
4497c478bd9Sstevel@tonic-gate  *	                ^maximum length
4507c478bd9Sstevel@tonic-gate  *
4517c478bd9Sstevel@tonic-gate  * Examples of mismatches:
4527c478bd9Sstevel@tonic-gate  *	" one"
4537c478bd9Sstevel@tonic-gate  *	"one"
4547c478bd9Sstevel@tonic-gate  *
4557c478bd9Sstevel@tonic-gate  *	"Number One    X|"
4567c478bd9Sstevel@tonic-gate  *	"Number One     |"
4577c478bd9Sstevel@tonic-gate  *	                ^maximum length
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate static int
4607c478bd9Sstevel@tonic-gate memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	uint_t		len, extra_len;
4637c478bd9Sstevel@tonic-gate 	char		*marker;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/* No point in comparing anything beyond max_sz */
4667c478bd9Sstevel@tonic-gate 	if (d1_len > max_sz)
4677c478bd9Sstevel@tonic-gate 		d1_len = max_sz;
4687c478bd9Sstevel@tonic-gate 	if (d2_len > max_sz)
4697c478bd9Sstevel@tonic-gate 		d2_len = max_sz;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/* Find shorter of the two data. */
4727c478bd9Sstevel@tonic-gate 	if (d1_len <= d2_len) {
4737c478bd9Sstevel@tonic-gate 		len = d1_len;
4747c478bd9Sstevel@tonic-gate 		extra_len = d2_len;
4757c478bd9Sstevel@tonic-gate 		marker = d2;
4767c478bd9Sstevel@tonic-gate 	} else {	/* d1_len > d2_len */
4777c478bd9Sstevel@tonic-gate 		len = d2_len;
4787c478bd9Sstevel@tonic-gate 		extra_len = d1_len;
4797c478bd9Sstevel@tonic-gate 		marker = d1;
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/* Have a match in the shortest length of data? */
4837c478bd9Sstevel@tonic-gate 	if (memcmp(d1, d2, len) != 0)
4847c478bd9Sstevel@tonic-gate 		/* CONSTCOND */
4857c478bd9Sstevel@tonic-gate 		return (!0);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* If the rest of longer data is nulls or blanks, call it a match. */
4887c478bd9Sstevel@tonic-gate 	while (len < extra_len)
4897c478bd9Sstevel@tonic-gate 		if (!isspace(marker[len++]))
4907c478bd9Sstevel@tonic-gate 			/* CONSTCOND */
4917c478bd9Sstevel@tonic-gate 			return (!0);
4927c478bd9Sstevel@tonic-gate 	return (0);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate /*
496*7711facfSdinak  * Locate a token slot whose token matches the label, manufacturer ID, and
497*7711facfSdinak  * serial number given.  Token label must be specified, manufacturer ID and
498*7711facfSdinak  * serial number are optional.  When the token is located, the PIN state
499*7711facfSdinak  * is also returned to determine if it still has the default PIN.
5007c478bd9Sstevel@tonic-gate  */
501*7711facfSdinak CK_RV
5027c478bd9Sstevel@tonic-gate find_token_slot(char *token_name, char *manuf_id, char *serial_no,
5037c478bd9Sstevel@tonic-gate 		CK_SLOT_ID *slot_id, CK_FLAGS *pin_state)
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate 	CK_SLOT_ID_PTR	slot_list;
5067c478bd9Sstevel@tonic-gate 	CK_TOKEN_INFO	token_info;
5077c478bd9Sstevel@tonic-gate 	CK_ULONG	slot_count = 0;
508*7711facfSdinak 	int		rv = CKR_OK;
5097c478bd9Sstevel@tonic-gate 	int		i;
5107c478bd9Sstevel@tonic-gate 	uint_t		len, max_sz;
5117c478bd9Sstevel@tonic-gate 	boolean_t	tok_match = B_FALSE,
5127c478bd9Sstevel@tonic-gate 			man_match = B_FALSE,
5137c478bd9Sstevel@tonic-gate 			ser_match = B_FALSE;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	cryptodebug("inside find_token_slot");
5167c478bd9Sstevel@tonic-gate 
517*7711facfSdinak 	if (token_name == NULL)
518*7711facfSdinak 		return (CKR_ARGUMENTS_BAD);
5197c478bd9Sstevel@tonic-gate 
520*7711facfSdinak 	/* Get a list of all slots with tokens present. */
521*7711facfSdinak 	if ((rv = get_token_slots(&slot_list, &slot_count)) != CKR_OK)
522*7711facfSdinak 		return (rv);
5237c478bd9Sstevel@tonic-gate 
524*7711facfSdinak 	/* If there are no such slots, the desired token won't be found. */
525*7711facfSdinak 	if (slot_count == 0)
526*7711facfSdinak 		return (CKR_TOKEN_NOT_PRESENT);
5277c478bd9Sstevel@tonic-gate 
528*7711facfSdinak 	/* Search the slot list for the token. */
5297c478bd9Sstevel@tonic-gate 	for (i = 0; i < slot_count; i++) {
530*7711facfSdinak 		cryptodebug("calling C_GetTokenInfo()");
531*7711facfSdinak 		if ((rv = C_GetTokenInfo(slot_list[i], &token_info)) !=
532*7711facfSdinak 		    CKR_OK) {
533*7711facfSdinak 			cryptodebug("token in slot %d returns %s", i,
534*7711facfSdinak 			    pkcs11_strerror(rv));
5357c478bd9Sstevel@tonic-gate 			continue;
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 
538*7711facfSdinak 		/* See if the token label matches. */
5397c478bd9Sstevel@tonic-gate 		len = strlen(token_name);
5407c478bd9Sstevel@tonic-gate 		max_sz = sizeof (token_info.label);
5417c478bd9Sstevel@tonic-gate 		if (memcmp_pad_max(&(token_info.label), max_sz, token_name, len,
5427c478bd9Sstevel@tonic-gate 		    max_sz) == 0)
5437c478bd9Sstevel@tonic-gate 			tok_match = B_TRUE;
5447c478bd9Sstevel@tonic-gate 
545*7711facfSdinak 		/*
546*7711facfSdinak 		 * If manufacturer id was given, see if it actually matches.
547*7711facfSdinak 		 * If no manufacturer id was given, assume match is true.
548*7711facfSdinak 		 */
5497c478bd9Sstevel@tonic-gate 		if (manuf_id) {
5507c478bd9Sstevel@tonic-gate 			len = strlen(manuf_id);
5517c478bd9Sstevel@tonic-gate 			max_sz = sizeof ((char *)(token_info.manufacturerID));
5527c478bd9Sstevel@tonic-gate 			if (memcmp_pad_max(&(token_info.manufacturerID), max_sz,
5537c478bd9Sstevel@tonic-gate 			    manuf_id, len, max_sz) == 0)
5547c478bd9Sstevel@tonic-gate 				man_match = B_TRUE;
555*7711facfSdinak 		} else
556*7711facfSdinak 			man_match = B_TRUE;
5577c478bd9Sstevel@tonic-gate 
558*7711facfSdinak 		/*
559*7711facfSdinak 		 * If serial number was given, see if it actually matches.
560*7711facfSdinak 		 * If no serial number was given, assume match is true.
561*7711facfSdinak 		 */
5627c478bd9Sstevel@tonic-gate 		if (serial_no) {
5637c478bd9Sstevel@tonic-gate 			len = strlen(serial_no);
5647c478bd9Sstevel@tonic-gate 			max_sz = sizeof ((char *)(token_info.serialNumber));
5657c478bd9Sstevel@tonic-gate 			if (memcmp_pad_max(&(token_info.serialNumber), max_sz,
5667c478bd9Sstevel@tonic-gate 			    serial_no, len, max_sz) == 0)
5677c478bd9Sstevel@tonic-gate 				ser_match = B_TRUE;
568*7711facfSdinak 		} else
569*7711facfSdinak 			ser_match = B_TRUE;
570*7711facfSdinak 
571*7711facfSdinak 		cryptodebug("slot %d:", i);
572*7711facfSdinak 		cryptodebug("\tlabel = \"%.32s\"%s", token_info.label,
573*7711facfSdinak 		    tok_match ? " match" : "");
574*7711facfSdinak 		cryptodebug("\tmanuf = \"%.32s\"%s", token_info.manufacturerID,
575*7711facfSdinak 		    man_match ? " match" : "");
576*7711facfSdinak 		cryptodebug("\tserno = \"%.16s\"%s", token_info.serialNumber,
577*7711facfSdinak 		    ser_match ? " match" : "");
578*7711facfSdinak 		cryptodebug("\tmodel = \"%.16s\"", token_info.model);
5797c478bd9Sstevel@tonic-gate 
580*7711facfSdinak 		cryptodebug("\tCKF_USER_PIN_INITIALIZED = %s",
581*7711facfSdinak 		    (token_info.flags & CKF_USER_PIN_INITIALIZED) ?
582*7711facfSdinak 		    "true" : "false");
583*7711facfSdinak 		cryptodebug("\tCKF_USER_PIN_TO_BE_CHANGED = %s",
584*7711facfSdinak 		    (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ?
585*7711facfSdinak 		    "true" : "false");
586*7711facfSdinak 
587*7711facfSdinak 		if (tok_match && man_match && ser_match)
588*7711facfSdinak 			break;		/* found it! */
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
591*7711facfSdinak 	/* Scanned the whole list without finding the token. */
5927c478bd9Sstevel@tonic-gate 	if (i == slot_count) {
593*7711facfSdinak 		cryptodebug("token not found");
5947c478bd9Sstevel@tonic-gate 		free(slot_list);
595*7711facfSdinak 		return (CKR_TOKEN_NOT_PRESENT);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 
598*7711facfSdinak 	/* Return slot id where token was found and its PIN state. */
599*7711facfSdinak 	cryptodebug("token found at slot %d", i);
6007c478bd9Sstevel@tonic-gate 	*slot_id = slot_list[i];
6017c478bd9Sstevel@tonic-gate 	*pin_state = (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED);
6027c478bd9Sstevel@tonic-gate 	free(slot_list);
603*7711facfSdinak 	return (CKR_OK);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /*
607*7711facfSdinak  * Constructs a fully qualified token name from its label, manufacturer ID
608*7711facfSdinak  * (if any), and its serial number (if any).  Note that the given buf must
609*7711facfSdinak  * be big enough.  Do NOT i18n/l10n.
610*7711facfSdinak  *
611*7711facfSdinak  * FULL_NAME_LEN is defined in common.h to be 91 because a fully qualified
612*7711facfSdinak  * token name adds up this way:
613*7711facfSdinak  * =32(label) + 32(manuf) + 16(serial) + 4("", ) + 4("", ) + 3("" and nul)
6147c478bd9Sstevel@tonic-gate  */
615*7711facfSdinak void
616*7711facfSdinak full_token_name(char *token_name, char *manuf_id, char *serial_no, char *buf)
6177c478bd9Sstevel@tonic-gate {
618*7711facfSdinak 	char		*marker = buf;
619*7711facfSdinak 	int		n_written = 0;
620*7711facfSdinak 	int		space_left = FULL_NAME_LEN;
6217c478bd9Sstevel@tonic-gate 
622*7711facfSdinak 	if (!token_name)
623*7711facfSdinak 		return;
624*7711facfSdinak 
625*7711facfSdinak 	n_written = sprintf(buf, "\"%.32s\"", token_name);
626*7711facfSdinak 	marker += n_written;
627*7711facfSdinak 	space_left -= n_written;
628*7711facfSdinak 
629*7711facfSdinak 	n_written = sprintf(marker, ", \"%.32s\"", manuf_id ? manuf_id : "");
630*7711facfSdinak 	marker += n_written;
631*7711facfSdinak 	space_left -= n_written;
6327c478bd9Sstevel@tonic-gate 
633*7711facfSdinak 	n_written = sprintf(marker, ", \"%.16s\"", serial_no ? serial_no : "");
634*7711facfSdinak 	marker += n_written;
635*7711facfSdinak 	space_left -= n_written;
636*7711facfSdinak 
637*7711facfSdinak 	/* space_left should always be >= 1 */
638*7711facfSdinak }
639*7711facfSdinak 
640*7711facfSdinak /*
641*7711facfSdinak  * Find how many token objects with the given label.
642*7711facfSdinak  */
643*7711facfSdinak CK_RV
644*7711facfSdinak find_obj_count(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label,
645*7711facfSdinak     CK_ULONG *count)
646*7711facfSdinak {
647*7711facfSdinak 	CK_RV			rv = CKR_OK;
648*7711facfSdinak 	CK_ATTRIBUTE		attrs[4] = {
649*7711facfSdinak 		{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
650*7711facfSdinak 		{ 0, NULL, 0 },
651*7711facfSdinak 		{ 0, NULL, 0 },
652*7711facfSdinak 		{ 0, NULL, 0 }
653*7711facfSdinak 	    };
654*7711facfSdinak 	CK_ULONG	num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
655*7711facfSdinak 	CK_ULONG	cur_attr = 1;		/* CKA_TOKEN already set */
656*7711facfSdinak 	CK_OBJECT_CLASS		obj_class;
657*7711facfSdinak 	CK_OBJECT_HANDLE	tmp_obj;
658*7711facfSdinak 	CK_ULONG		obj_count = 0;
659*7711facfSdinak 
660*7711facfSdinak 	cryptodebug("inside find_obj_count");
661*7711facfSdinak 
662*7711facfSdinak 	if (!session_opened || sess == NULL) {
663*7711facfSdinak 		cryptodebug("session handle is null");
664*7711facfSdinak 		return (CKR_SESSION_HANDLE_INVALID);
665*7711facfSdinak 	}
666*7711facfSdinak 
667*7711facfSdinak 	if (label) {
668*7711facfSdinak 		cryptodebug("object label was specified");
669*7711facfSdinak 		attrs[cur_attr].type = CKA_LABEL;
670*7711facfSdinak 		attrs[cur_attr].pValue = label;
671*7711facfSdinak 		attrs[cur_attr].ulValueLen = strlen((char *)label);
672*7711facfSdinak 		cur_attr++;
673*7711facfSdinak 	}
674*7711facfSdinak 
675*7711facfSdinak 	if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) {
676*7711facfSdinak 		cryptodebug("only searching for private objects");
677*7711facfSdinak 		attrs[cur_attr].type = CKA_PRIVATE;
678*7711facfSdinak 		attrs[cur_attr].pValue = &pk_true;
679*7711facfSdinak 		attrs[cur_attr].ulValueLen = sizeof (pk_true);
680*7711facfSdinak 		cur_attr++;
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/*
684*7711facfSdinak 	 * If "certs and all keys" is not specified, but at least either
685*7711facfSdinak 	 * "certs" or some "keys" is specified, then go into this block.
686*7711facfSdinak 	 * If all certs and keys were specified, there's no point in
687*7711facfSdinak 	 * putting that fact in the attribute template -- leave that open,
688*7711facfSdinak 	 * and all certs and keys will be matched automatically.
689*7711facfSdinak 	 * In other words, only if at least one of 0x10,0x20,0x40,0x80
690*7711facfSdinak 	 * bits is off, go into this code block.
691*7711facfSdinak 	 *
692*7711facfSdinak 	 * NOTE:  For now, only one of cert or key types is allowed.
693*7711facfSdinak 	 * This needs to change in the future.
6947c478bd9Sstevel@tonic-gate 	 */
695*7711facfSdinak 	if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) &&
696*7711facfSdinak 	    ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) {
697*7711facfSdinak 		if (obj_type & PK_CERT_OBJ) {
698*7711facfSdinak 			cryptodebug("only searching for certificates");
699*7711facfSdinak 			obj_class = CKO_CERTIFICATE;
700*7711facfSdinak 		} else if (obj_type & PK_PRIKEY_OBJ) {
701*7711facfSdinak 			cryptodebug("only searching for private keys");
702*7711facfSdinak 			obj_class = CKO_PRIVATE_KEY;
703*7711facfSdinak 		} else if (obj_type & PK_PUBKEY_OBJ) {
704*7711facfSdinak 			cryptodebug("only searching for public keys");
705*7711facfSdinak 			obj_class = CKO_PUBLIC_KEY;
706*7711facfSdinak 		} else if (obj_type & PK_SECKEY_OBJ) {
707*7711facfSdinak 			cryptodebug("only searching for secret keys");
708*7711facfSdinak 			obj_class = CKO_SECRET_KEY;
709*7711facfSdinak 		}
710*7711facfSdinak 
711*7711facfSdinak 		attrs[cur_attr].type = CKA_CLASS;
712*7711facfSdinak 		attrs[cur_attr].pValue = &obj_class;
713*7711facfSdinak 		attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS);
714*7711facfSdinak 		cur_attr++;
715*7711facfSdinak 	}
716*7711facfSdinak 
717*7711facfSdinak 	/*
718*7711facfSdinak 	 * This can't happen now.  When finding objects is enhanced in the
719*7711facfSdinak 	 * future. this could lead to buffer overruns.
720*7711facfSdinak 	 */
721*7711facfSdinak 	if (cur_attr > num_attrs)
722*7711facfSdinak 		cryptodebug("internal error:  attr template overrun");
723*7711facfSdinak 
724*7711facfSdinak 	cryptodebug("calling C_FindObjectsInit");
725*7711facfSdinak 	if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK)
726*7711facfSdinak 		return (rv);
727*7711facfSdinak 
728*7711facfSdinak 	/* Look for the object, checking if there are more than one. */
729*7711facfSdinak 	cryptodebug("calling C_FindObjects");
730*7711facfSdinak 	for (*count = 0; /* empty */; (*count)++) {
731*7711facfSdinak 		if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) !=
732*7711facfSdinak 		    CKR_OK)
733*7711facfSdinak 			break;
734*7711facfSdinak 
735*7711facfSdinak 		/* No more found. */
736*7711facfSdinak 		if (obj_count == 0)
737*7711facfSdinak 			break;
738*7711facfSdinak 	}
739*7711facfSdinak 
740*7711facfSdinak 	cryptodebug("%d matching objects found", *count);
741*7711facfSdinak 
742*7711facfSdinak 	cryptodebug("calling C_FindObjectsFinal");
743*7711facfSdinak 	(void) C_FindObjectsFinal(sess);
744*7711facfSdinak 	return (rv);
745*7711facfSdinak }
746*7711facfSdinak 
747*7711facfSdinak /*
748*7711facfSdinak  * Find the token object with the given label.
749*7711facfSdinak  */
750*7711facfSdinak CK_RV
751*7711facfSdinak find_objs(CK_SESSION_HANDLE sess, int obj_type, CK_BYTE *label,
752*7711facfSdinak     CK_OBJECT_HANDLE_PTR *obj, CK_ULONG *count)
753*7711facfSdinak {
754*7711facfSdinak 	CK_RV			rv = CKR_OK;
755*7711facfSdinak 	CK_ATTRIBUTE		attrs[4] = {
756*7711facfSdinak 		{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
757*7711facfSdinak 		{ 0, NULL, 0 },
758*7711facfSdinak 		{ 0, NULL, 0 },
759*7711facfSdinak 		{ 0, NULL, 0 }
760*7711facfSdinak 	    };
761*7711facfSdinak 	CK_ULONG	num_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
762*7711facfSdinak 	CK_ULONG	cur_attr = 1;		/* CKA_TOKEN already set */
763*7711facfSdinak 	CK_OBJECT_CLASS		obj_class;
764*7711facfSdinak 	CK_OBJECT_HANDLE	tmp_obj;
765*7711facfSdinak 	CK_ULONG		obj_count = 0;
766*7711facfSdinak 	int			i;
767*7711facfSdinak 
768*7711facfSdinak 	cryptodebug("inside find_obj");
769*7711facfSdinak 
770*7711facfSdinak 	if ((rv = find_obj_count(sess, obj_type, label, count)) != CKR_OK)
771*7711facfSdinak 		return (rv);
772*7711facfSdinak 
773*7711facfSdinak 	if (*count == 0)
774*7711facfSdinak 		return (CKR_OK);
775*7711facfSdinak 
776*7711facfSdinak 	if ((*obj = (CK_OBJECT_HANDLE_PTR) malloc((*count) *
777*7711facfSdinak 	    sizeof (CK_OBJECT_HANDLE))) == NULL) {
778*7711facfSdinak 		cryptodebug("no memory for found object");
779*7711facfSdinak 		return (CKR_HOST_MEMORY);
780*7711facfSdinak 	}
781*7711facfSdinak 
782*7711facfSdinak 	if (label) {
783*7711facfSdinak 		cryptodebug("object label was specified");
784*7711facfSdinak 		attrs[cur_attr].type = CKA_LABEL;
785*7711facfSdinak 		attrs[cur_attr].pValue = label;
786*7711facfSdinak 		attrs[cur_attr].ulValueLen = strlen((char *)label);
787*7711facfSdinak 		cur_attr++;
788*7711facfSdinak 	}
789*7711facfSdinak 
790*7711facfSdinak 	if ((obj_type & PK_PRIVATE_OBJ) && !(obj_type & PK_PUBLIC_OBJ)) {
791*7711facfSdinak 		cryptodebug("only searching for private objects");
792*7711facfSdinak 		attrs[cur_attr].type = CKA_PRIVATE;
793*7711facfSdinak 		attrs[cur_attr].pValue = &pk_true;
794*7711facfSdinak 		attrs[cur_attr].ulValueLen = sizeof (pk_true);
795*7711facfSdinak 		cur_attr++;
796*7711facfSdinak 	}
797*7711facfSdinak 
798*7711facfSdinak 	/*
799*7711facfSdinak 	 * If "certs and all keys" is not specified, but at least either
800*7711facfSdinak 	 * "certs" or some "keys" is specified, then go into this block.
801*7711facfSdinak 	 * If all certs and keys were specified, there's no point in
802*7711facfSdinak 	 * putting that fact in the attribute template -- leave that open,
803*7711facfSdinak 	 * and all certs and keys will be matched automatically.
804*7711facfSdinak 	 * In other words, only if at least one of 0x10,0x20,0x40,0x80
805*7711facfSdinak 	 * bits is off, go into this code block.
806*7711facfSdinak 	 *
807*7711facfSdinak 	 * NOTE:  For now, only one of cert or key types is allowed.
808*7711facfSdinak 	 * This needs to change in the future.
809*7711facfSdinak 	 */
810*7711facfSdinak 	if ((obj_type & (PK_CERT_OBJ|PK_KEY_OBJ)) != (PK_CERT_OBJ|PK_KEY_OBJ) &&
811*7711facfSdinak 	    ((obj_type & PK_CERT_OBJ) || (obj_type & PK_KEY_OBJ))) {
812*7711facfSdinak 		if (obj_type & PK_CERT_OBJ) {
813*7711facfSdinak 			cryptodebug("only searching for certificates");
814*7711facfSdinak 			obj_class = CKO_CERTIFICATE;
815*7711facfSdinak 		} else if (obj_type & PK_PRIKEY_OBJ) {
816*7711facfSdinak 			cryptodebug("only searching for private keys");
817*7711facfSdinak 			obj_class = CKO_PRIVATE_KEY;
818*7711facfSdinak 		} else if (obj_type & PK_PUBKEY_OBJ) {
819*7711facfSdinak 			cryptodebug("only searching for public keys");
820*7711facfSdinak 			obj_class = CKO_PUBLIC_KEY;
821*7711facfSdinak 		} else if (obj_type & PK_SECKEY_OBJ) {
822*7711facfSdinak 			cryptodebug("only searching for secret keys");
823*7711facfSdinak 			obj_class = CKO_SECRET_KEY;
824*7711facfSdinak 		}
825*7711facfSdinak 
826*7711facfSdinak 		attrs[cur_attr].type = CKA_CLASS;
827*7711facfSdinak 		attrs[cur_attr].pValue = &obj_class;
828*7711facfSdinak 		attrs[cur_attr].ulValueLen = sizeof (CK_OBJECT_CLASS);
829*7711facfSdinak 		cur_attr++;
830*7711facfSdinak 	}
831*7711facfSdinak 
832*7711facfSdinak 	/*
833*7711facfSdinak 	 * This can't happen now.  When finding objects is enhanced in the
834*7711facfSdinak 	 * future. this could lead to buffer overruns.
835*7711facfSdinak 	 */
836*7711facfSdinak 	if (cur_attr > num_attrs)
837*7711facfSdinak 		cryptodebug("internal error:  attr template overrun");
838*7711facfSdinak 
839*7711facfSdinak 	cryptodebug("calling C_FindObjectsInit");
840*7711facfSdinak 	if ((rv = C_FindObjectsInit(sess, attrs, cur_attr)) != CKR_OK) {
841*7711facfSdinak 		free(*obj);
842*7711facfSdinak 		return (rv);
843*7711facfSdinak 	}
844*7711facfSdinak 
845*7711facfSdinak 	/*
846*7711facfSdinak 	 * Find all the matching objects.  The loop goes 1 more beyond
847*7711facfSdinak 	 * the number of objects found to determine if any new objects
848*7711facfSdinak 	 * were created since the time the object count was done.
849*7711facfSdinak 	 */
850*7711facfSdinak 	cryptodebug("calling C_FindObjects");
851*7711facfSdinak 	for (i = 0; i < (*count) + 1; i++) {
852*7711facfSdinak 		if ((rv = C_FindObjects(sess, &tmp_obj, 1, &obj_count)) !=
853*7711facfSdinak 		    CKR_OK)
854*7711facfSdinak 			break;
855*7711facfSdinak 
856*7711facfSdinak 		/* No more found. */
857*7711facfSdinak 		if (obj_count == 0)
858*7711facfSdinak 			break;
859*7711facfSdinak 
860*7711facfSdinak 		/*
861*7711facfSdinak 		 * Save the object in the list being created, as long as
862*7711facfSdinak 		 * we don't overrun the size of the list.
863*7711facfSdinak 		 */
864*7711facfSdinak 		if (i < *count)
865*7711facfSdinak 		    (*obj)[i] = tmp_obj;
866*7711facfSdinak 		else
867*7711facfSdinak 		    cryptodebug("number of objects changed since last count");
868*7711facfSdinak 	}
869*7711facfSdinak 
870*7711facfSdinak 	if (rv != CKR_OK) {
871*7711facfSdinak 		free(*obj);
872*7711facfSdinak 	} else {
873*7711facfSdinak 		/*
874*7711facfSdinak 		 * There are three cases to handle:  (1) fewer objects were
875*7711facfSdinak 		 * found than originally counted => change *count to the
876*7711facfSdinak 		 * smaller number; (2) the number of objects found matches
877*7711facfSdinak 		 * the number originally counted => do nothing; (3) more
878*7711facfSdinak 		 * objects found than originally counted => list passed
879*7711facfSdinak 		 * in is too small to contain the extra object(s), flag
880*7711facfSdinak 		 * that in the debug output but don't change number of
881*7711facfSdinak 		 * objects returned.  The caller can double-check by
882*7711facfSdinak 		 * calling find_obj_count() after this function to make
883*7711facfSdinak 		 * sure the numbers match, if desired.
884*7711facfSdinak 		 */
885*7711facfSdinak 		/* Case 1:  Fewer objects. */
886*7711facfSdinak 		if (i < *count) {
887*7711facfSdinak 			cryptodebug("%d objects found, expected %d", i, *count);
888*7711facfSdinak 			*count = i;
889*7711facfSdinak 		/* Case 3:  More objects. */
890*7711facfSdinak 		} else if (i > *count) {
891*7711facfSdinak 			cryptodebug("at least %d objects found, expected %d",
892*7711facfSdinak 			    i, *count);
893*7711facfSdinak 		}
894*7711facfSdinak 		/*
895*7711facfSdinak 		 * Case 2:  Same number of objects.
896*7711facfSdinak 		 *
897*7711facfSdinak 		 * else if (i == *count)
898*7711facfSdinak 		 *	;
899*7711facfSdinak 		 */
900*7711facfSdinak 	}
901*7711facfSdinak 
902*7711facfSdinak 	cryptodebug("calling C_FindObjectsFinal");
903*7711facfSdinak 	(void) C_FindObjectsFinal(sess);
904*7711facfSdinak 	return (rv);
905*7711facfSdinak }
906*7711facfSdinak 
907*7711facfSdinak char *
908*7711facfSdinak class_str(CK_OBJECT_CLASS class)
909*7711facfSdinak {
910*7711facfSdinak 	switch (class) {
911*7711facfSdinak 	case CKO_DATA:		return (gettext("data"));
912*7711facfSdinak 	case CKO_CERTIFICATE:	return (gettext("certificate"));
913*7711facfSdinak 	case CKO_PUBLIC_KEY:	return (gettext("public key"));
914*7711facfSdinak 	case CKO_PRIVATE_KEY:	return (gettext("private key"));
915*7711facfSdinak 	case CKO_SECRET_KEY:	return (gettext("secret key"));
916*7711facfSdinak 	case CKO_DOMAIN_PARAMETERS:	return (gettext("domain parameter"));
917*7711facfSdinak 	default:		return (gettext("unknown object"));
918*7711facfSdinak 	}
919*7711facfSdinak }
920*7711facfSdinak 
921*7711facfSdinak char *
922*7711facfSdinak keytype_str(CK_KEY_TYPE keytype)
923*7711facfSdinak {
924*7711facfSdinak 	switch (keytype) {
925*7711facfSdinak 	case CKK_RSA:		return (gettext("RSA"));
926*7711facfSdinak 	case CKK_DSA:		return (gettext("DSA"));
927*7711facfSdinak 	case CKK_DH:		return (gettext("Diffie-Hellman"));
928*7711facfSdinak 	case CKK_X9_42_DH:	return (gettext("X9.42 Diffie-Hellman"));
929*7711facfSdinak 	case CKK_GENERIC_SECRET:	return (gettext("generic"));
930*7711facfSdinak 	case CKK_RC2:		return (gettext("RC2"));
931*7711facfSdinak 	case CKK_RC4:		return (gettext("RC4"));
932*7711facfSdinak 	case CKK_DES:		return (gettext("DES"));
933*7711facfSdinak 	case CKK_DES2:		return (gettext("Double-DES"));
934*7711facfSdinak 	case CKK_DES3:		return (gettext("Triple-DES"));
935*7711facfSdinak 	case CKK_RC5:		return (gettext("RC5"));
936*7711facfSdinak 	case CKK_AES:		return (gettext("AES"));
937*7711facfSdinak 	default:		return (gettext("typeless"));
9387c478bd9Sstevel@tonic-gate 	}
939*7711facfSdinak }
9407c478bd9Sstevel@tonic-gate 
941*7711facfSdinak char *
942*7711facfSdinak attr_str(CK_ATTRIBUTE_TYPE attrtype)
943*7711facfSdinak {
944*7711facfSdinak 	switch (attrtype) {
945*7711facfSdinak 	case CKA_PRIVATE:		return (gettext("private"));
946*7711facfSdinak 	case CKA_LOCAL:			return (gettext("local"));
947*7711facfSdinak 	case CKA_SENSITIVE:		return (gettext("sensitive"));
948*7711facfSdinak 	case CKA_EXTRACTABLE:		return (gettext("extractable"));
949*7711facfSdinak 	case CKA_ENCRYPT:		return (gettext("encrypt"));
950*7711facfSdinak 	case CKA_DECRYPT:		return (gettext("decrypt"));
951*7711facfSdinak 	case CKA_WRAP:			return (gettext("wrap"));
952*7711facfSdinak 	case CKA_UNWRAP:		return (gettext("unwrap"));
953*7711facfSdinak 	case CKA_SIGN:			return (gettext("sign"));
954*7711facfSdinak 	case CKA_SIGN_RECOVER:		return (gettext("sign-recover"));
955*7711facfSdinak 	case CKA_VERIFY:		return (gettext("verify"));
956*7711facfSdinak 	case CKA_VERIFY_RECOVER:	return (gettext("verify-recover"));
957*7711facfSdinak 	case CKA_DERIVE:		return (gettext("derive"));
958*7711facfSdinak 	case CKA_ALWAYS_SENSITIVE:	return (gettext("always sensitive"));
959*7711facfSdinak 	case CKA_NEVER_EXTRACTABLE:	return (gettext("never extractable"));
960*7711facfSdinak 	default:		return (gettext("unknown capability"));
961*7711facfSdinak 	}
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*
965*7711facfSdinak  * Convert a byte string into a string of octets formatted like this:
966*7711facfSdinak  *	oo oo oo oo oo ... oo
967*7711facfSdinak  * where each "oo" is an octet is space separated and in the form:
968*7711facfSdinak  *	[0-f][0-f] if the octet is a non-printable character
969*7711facfSdinak  *	<space><char> if the octet is a printable character
970*7711facfSdinak  *
971*7711facfSdinak  * Note:  octets_sz must be 3 * str_sz + 1, or at least as long as "blank"
9727c478bd9Sstevel@tonic-gate  */
9737c478bd9Sstevel@tonic-gate void
974*7711facfSdinak octetify(CK_BYTE *str, CK_ULONG str_sz, char *octets, int octets_sz,
975*7711facfSdinak     boolean_t stop_on_nul, boolean_t do_ascii, int limit, char *indent,
976*7711facfSdinak     char *blank)
9777c478bd9Sstevel@tonic-gate {
978*7711facfSdinak 	char		*marker;
979*7711facfSdinak 	int		nc;
980*7711facfSdinak 	int		newline;
981*7711facfSdinak 	int		indent_len;
982*7711facfSdinak 	boolean_t	first = B_TRUE;
983*7711facfSdinak 
984*7711facfSdinak 	cryptodebug("inside octetify");
985*7711facfSdinak 
986*7711facfSdinak 	cryptodebug(stop_on_nul ? "stopping on first nul found" :
987*7711facfSdinak 	    "continuing to full length of buffer");
988*7711facfSdinak 	cryptodebug(do_ascii ? "using ascii chars where printable" :
989*7711facfSdinak 	    "using only hex octets");
990*7711facfSdinak 	cryptodebug("every %d characters indent with \"%s\"\n ", limit, indent);
991*7711facfSdinak 	cryptodebug("return \"%s\" if buffer is null or empty", blank);
9927c478bd9Sstevel@tonic-gate 
993*7711facfSdinak 	/* If string is empty, write as much of the blank string and leave. */
994*7711facfSdinak 	if (str_sz == 0) {
995*7711facfSdinak 		(void) snprintf(octets, octets_sz, "%s", blank);
996*7711facfSdinak 		return;
9977c478bd9Sstevel@tonic-gate 	}
998*7711facfSdinak 
999*7711facfSdinak 	/* If only limit or indent is set, pick default for the other. */
1000*7711facfSdinak 	if (limit > 0 && indent == NULL)
1001*7711facfSdinak 		indent = "\n";
1002*7711facfSdinak 	if (indent != NULL && limit == 0)
1003*7711facfSdinak 		limit = 60;
1004*7711facfSdinak 	indent_len = strlen(indent);
1005*7711facfSdinak 
1006*7711facfSdinak 	for (marker = octets, newline = 0, first = B_TRUE;
1007*7711facfSdinak 	    (stop_on_nul && *str != '\0') ||
1008*7711facfSdinak 	    (!stop_on_nul && str_sz > 0 && octets_sz > 0);
1009*7711facfSdinak 	    str++, str_sz--, marker += nc, octets_sz -= nc) {
1010*7711facfSdinak 		if (!first) {
1011*7711facfSdinak 			if (limit > 0 && ((marker - octets) / limit) >
1012*7711facfSdinak 			    newline) {
1013*7711facfSdinak 				nc = snprintf(marker, indent_len, "%s", indent);
1014*7711facfSdinak 				newline++;
1015*7711facfSdinak 				continue;
1016*7711facfSdinak 			}
1017*7711facfSdinak 			nc = sprintf(marker,
1018*7711facfSdinak 			    ((do_ascii && isprint(*str) && !isspace(*str)) ?
1019*7711facfSdinak 			    "%s%c" : "%s%02x"), (do_ascii ? " " : ":"), *str);
1020*7711facfSdinak 		} else {
1021*7711facfSdinak 			nc = sprintf(marker,
1022*7711facfSdinak 			    ((do_ascii && isprint(*str) && !isspace(*str)) ?
1023*7711facfSdinak 			    "%c" : "%02x"), *str);
1024*7711facfSdinak 			first = B_FALSE;
1025*7711facfSdinak 		}
1026*7711facfSdinak 	}
1027*7711facfSdinak 	*marker = '\0';
1028*7711facfSdinak }
1029*7711facfSdinak 
1030*7711facfSdinak /*
1031*7711facfSdinak  * Copies a biginteger_t to a template attribute.
1032*7711facfSdinak  * Should be a macro instead of a function.
1033*7711facfSdinak  */
1034*7711facfSdinak void
1035*7711facfSdinak copy_bigint_to_attr(biginteger_t big, CK_ATTRIBUTE_PTR attr)
1036*7711facfSdinak {
1037*7711facfSdinak 	attr->pValue = big.big_value;
1038*7711facfSdinak 	attr->ulValueLen = big.big_value_len;
1039*7711facfSdinak }
1040*7711facfSdinak 
1041*7711facfSdinak /*
1042*7711facfSdinak  * Copies a string and its length to a template attribute.
1043*7711facfSdinak  * Should be a macro instead of a function.
1044*7711facfSdinak  */
1045*7711facfSdinak void
1046*7711facfSdinak copy_string_to_attr(CK_BYTE *buf, CK_ULONG buflen, CK_ATTRIBUTE_PTR attr)
1047*7711facfSdinak {
1048*7711facfSdinak 	attr->pValue = buf;
1049*7711facfSdinak 	attr->ulValueLen = buflen;
1050*7711facfSdinak }
1051*7711facfSdinak 
1052*7711facfSdinak /*
1053*7711facfSdinak  * Copies a template attribute to a biginteger_t.
1054*7711facfSdinak  * Should be a macro instead of a function.
1055*7711facfSdinak  */
1056*7711facfSdinak void
1057*7711facfSdinak copy_attr_to_bigint(CK_ATTRIBUTE_PTR attr, biginteger_t *big)
1058*7711facfSdinak {
1059*7711facfSdinak 	big->big_value = attr->pValue;
1060*7711facfSdinak 	big->big_value_len = attr->ulValueLen;
1061*7711facfSdinak }
1062*7711facfSdinak 
1063*7711facfSdinak /*
1064*7711facfSdinak  * Copies a template attribute to a string and its length.
1065*7711facfSdinak  * Should be a macro instead of a function.
1066*7711facfSdinak  */
1067*7711facfSdinak void
1068*7711facfSdinak copy_attr_to_string(CK_ATTRIBUTE_PTR attr, CK_BYTE **buf, CK_ULONG *buflen)
1069*7711facfSdinak {
1070*7711facfSdinak 	*buf = attr->pValue;
1071*7711facfSdinak 	*buflen = attr->ulValueLen;
1072*7711facfSdinak }
1073*7711facfSdinak 
1074*7711facfSdinak /*
1075*7711facfSdinak  * Copies a template attribute to a date and its length.
1076*7711facfSdinak  * Should be a macro instead of a function.
1077*7711facfSdinak  */
1078*7711facfSdinak void
1079*7711facfSdinak copy_attr_to_date(CK_ATTRIBUTE_PTR attr, CK_DATE **buf, CK_ULONG *buflen)
1080*7711facfSdinak {
1081*7711facfSdinak 	*buf = (CK_DATE *)attr->pValue;
1082*7711facfSdinak 	*buflen = attr->ulValueLen;
10837c478bd9Sstevel@tonic-gate }
1084