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