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