xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/list.c (revision ba1637f8b78b432c41b36839c92aecf1f5f9fafb)
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 implements the token object list operation for this tool.
31  * It loads the PKCS#11 modules, finds the object to list, lists it,
32  * and cleans up.  User must be logged into the token to list private
33  * objects.
34  */
35 
36 #include <stdio.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <cryptoutil.h>
40 #include <security/cryptoki.h>
41 #include "common.h"
42 #include "derparse.h"
43 
44 /*
45  * Get key size based on the key type.
46  */
47 static CK_ULONG
48 get_key_size(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, CK_KEY_TYPE key_type)
49 {
50 	CK_RV		rv = CKR_OK;
51 	CK_ULONG	key_size;
52 	CK_ATTRIBUTE	modulus_sz =
53 		{ CKA_MODULUS, NULL, 0 };	/* RSA */
54 	CK_ATTRIBUTE	prime_sz =
55 		{ CKA_PRIME, NULL, 0 };		/* DSA, DH X9.42 */
56 	CK_ATTRIBUTE	value_sz =
57 		{ CKA_VALUE, NULL_PTR, 0 };	/* DH, DES/DES3, AES, GENERIC */
58 
59 	cryptodebug("inside get_key_size");
60 
61 	switch (key_type) {
62 	case CKK_RSA:
63 		if ((rv = C_GetAttributeValue(sess, obj, &modulus_sz, 1)) !=
64 		    CKR_OK) {
65 			cryptoerror(LOG_STDERR, gettext(
66 			    "Unable to get modulus attribute size (%s)."),
67 			    pkcs11_strerror(rv));
68 		} else
69 			/* Convert key size to bits. */
70 			key_size = modulus_sz.ulValueLen * 8;
71 		break;
72 	case CKK_DH:
73 		if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
74 		    CKR_OK) {
75 			cryptoerror(LOG_STDERR, gettext(
76 			    "Unable to get value attribute size (%s)."),
77 			    pkcs11_strerror(rv));
78 		} else
79 			/* Convert key size to bits. */
80 			key_size = value_sz.ulValueLen * 8;
81 		break;
82 	case CKK_X9_42_DH:
83 	case CKK_DSA:
84 		if ((rv = C_GetAttributeValue(sess, obj, &prime_sz, 1)) !=
85 		    CKR_OK) {
86 			cryptoerror(LOG_STDERR, gettext(
87 			    "Unable to get prime attribute size (%s)."),
88 			    pkcs11_strerror(rv));
89 		} else
90 			/* Convert key size to bits. */
91 			key_size = prime_sz.ulValueLen * 8;
92 		break;
93 	case CKK_DES:
94 	case CKK_DES3:
95 		if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
96 		    CKR_OK) {
97 			cryptoerror(LOG_STDERR, gettext(
98 			    "Unable to get value attribute size (%s)."),
99 			    pkcs11_strerror(rv));
100 		} else
101 			/* Convert key size to bits -- omitting parity bit. */
102 			key_size = value_sz.ulValueLen * 7;
103 		break;
104 	case CKK_AES:
105 	case CKK_GENERIC_SECRET:
106 		if ((rv = C_GetAttributeValue(sess, obj, &value_sz, 1)) !=
107 		    CKR_OK) {
108 			cryptoerror(LOG_STDERR, gettext(
109 			    "Unable to get value attribute size (%s)."),
110 			    pkcs11_strerror(rv));
111 		} else
112 			/* Convert key size to bits. */
113 			key_size = value_sz.ulValueLen * 8;
114 		break;
115 	default:
116 		cryptoerror(LOG_STDERR, gettext(
117 		    "Unknown object key type (0x%02x)."), key_type);
118 		break;
119 	}
120 
121 	return (key_size);
122 }
123 
124 /*
125  * Display private key.
126  */
127 static CK_RV
128 display_prikey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
129 {
130 	CK_RV			rv = CKR_OK;
131 	static CK_BBOOL		private;
132 	static CK_BBOOL		modifiable;
133 	static CK_KEY_TYPE	key_type;
134 	CK_ULONG		key_size;
135 	CK_BYTE			*label = NULL;
136 	CK_ULONG		label_len = 0;
137 	CK_BYTE			*id = NULL;
138 	CK_ULONG		id_len = 0;
139 	CK_BYTE			*subject = NULL;
140 	CK_ULONG		subject_len = 0;
141 	CK_DATE			*start_date = NULL;
142 	CK_ULONG		start_date_len = 0;
143 	CK_DATE			*end_date = NULL;
144 	CK_ULONG		end_date_len = 0;
145 	CK_ATTRIBUTE		attrs[18] = {
146 		/* 0 to 2 */
147 		{ CKA_PRIVATE, &private, sizeof (private) },
148 		{ CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
149 		{ CKA_KEY_TYPE, &key_type, sizeof (key_type) },
150 		/* 3 to 12 */
151 		{ CKA_DERIVE, NULL, 0 },
152 		{ CKA_LOCAL, NULL, 0 },
153 		{ CKA_DECRYPT, NULL, 0 },
154 		{ CKA_SIGN, NULL, 0 },
155 		{ CKA_SIGN_RECOVER, NULL, 0 },
156 		{ CKA_UNWRAP, NULL, 0 },
157 		{ CKA_SENSITIVE, NULL, 0 },
158 		{ CKA_ALWAYS_SENSITIVE, NULL, 0 },
159 		{ CKA_EXTRACTABLE, NULL, 0 },
160 		{ CKA_NEVER_EXTRACTABLE, NULL, 0 },
161 		/* 13 to 17 */
162 		{ CKA_LABEL, NULL, 0 },			/* optional */
163 		{ CKA_ID, NULL, 0 },			/* optional */
164 		{ CKA_SUBJECT, NULL, 0 },		/* optional */
165 		{ CKA_START_DATE, NULL, 0 },		/* optional */
166 		{ CKA_END_DATE, NULL, 0 }		/* optional */
167 		/* not displaying CKA_KEY_GEN_MECHANISM */
168 	    };
169 	CK_ULONG	n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
170 	int		i;
171 	char		*hex_id = NULL;
172 	int		hex_id_len = 0;
173 	char		*hex_subject = NULL;
174 	int		hex_subject_len = 0;
175 
176 	cryptodebug("inside display_prikey");
177 
178 	/* Get the sizes of the attributes we need. */
179 	cryptodebug("calling C_GetAttributeValue for size info");
180 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
181 		cryptoerror(LOG_STDERR, gettext(
182 		    "Unable to get private key attribute sizes (%s)."),
183 		    pkcs11_strerror(rv));
184 		return (rv);
185 	}
186 
187 	/* Allocate memory for each variable-length attribute. */
188 	for (i = 3; i < n_attrs; i++) {
189 		if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
190 		    attrs[i].ulValueLen == 0) {
191 			cryptodebug("display_prikey: *** should not happen");
192 			attrs[i].ulValueLen = 0;
193 			continue;
194 		}
195 		if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
196 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
197 			rv = CKR_HOST_MEMORY;
198 			goto free_display_prikey;
199 		}
200 	}
201 
202 	/* Now really get the attributes. */
203 	cryptodebug("calling C_GetAttributeValue for attribute info");
204 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
205 		cryptoerror(LOG_STDERR, gettext(
206 		    "Unable to get private key attributes (%s)."),
207 		    pkcs11_strerror(rv));
208 		goto free_display_prikey;
209 	}
210 
211 	/* Fill in all the optional temp variables. */
212 	i = 13;
213 	copy_attr_to_string(&(attrs[i++]), &label, &label_len);
214 	copy_attr_to_string(&(attrs[i++]), &id, &id_len);
215 	copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
216 	copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
217 	copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
218 
219 	/* Get the key size for the object. */
220 	key_size = get_key_size(sess, obj, key_type);
221 
222 	/* Display the object ... */
223 		/* ... the label and what it is (and key size in bits) ... */
224 	(void) fprintf(stdout, gettext("%d.  \"%.*s\" (%d-bit %s %s)\n"),
225 	    counter, label_len, label_len > 0 ? (char *)label :
226 	    gettext("<no label>"), key_size, keytype_str(key_type),
227 	    class_str(CKO_PRIVATE_KEY));
228 
229 		/* ... the id ... */
230 	if (id_len == (CK_ULONG)-1 || id_len == 0)
231 		(void) fprintf(stdout, gettext("\tId:  --\n"));
232 	else {
233 		hex_id_len = 3 * id_len + 1;
234 		if ((hex_id = malloc(hex_id_len)) == NULL) {
235 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
236 			rv = CKR_HOST_MEMORY;
237 			goto free_display_prikey;
238 		}
239 		octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
240 		    "\n\t\t", "");
241 		(void) fprintf(stdout, gettext("\tId:  %s\n"), hex_id);
242 		free(hex_id);
243 	}
244 
245 		/* ... the subject name ... */
246 	if (subject_len == (CK_ULONG)-1 || subject_len == 0)
247 		(void) fprintf(stdout, gettext("\tSubject:  --\n"));
248 	else {
249 		hex_subject_len = 2 * subject_len + 1;	/* best guesstimate */
250 		if ((hex_subject = malloc(hex_subject_len)) == NULL) {
251 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
252 			rv = CKR_HOST_MEMORY;
253 			goto free_display_prikey;
254 		}
255 		rdnseq_to_str(subject, subject_len, hex_subject,
256 		    hex_subject_len);
257 		(void) fprintf(stdout, gettext("\tSubject:  %.*s\n"),
258 		    hex_subject_len, hex_subject);
259 		free(hex_subject);
260 	}
261 
262 		/* ... the start date ... */
263 	if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
264 		(void) fprintf(stdout, gettext("\tStart Date:  --\n"));
265 	else
266 		(void) fprintf(stdout, gettext(
267 		    "\tStart Date:  %02.2s/%02.2s/%04.4s\n"),
268 		    start_date->month, start_date->day, start_date->year);
269 
270 		/* ... the end date ... */
271 	if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
272 		(void) fprintf(stdout, gettext("\tEnd Date:  --\n"));
273 	else
274 		(void) fprintf(stdout, gettext(
275 		    "\tEnd Date:  %02.2s/%02.2s/%04.4s\n"),
276 		    end_date->month, end_date->day, end_date->year);
277 
278 		/* ... and its capabilities */
279 	(void) fprintf(stdout, "\t(%s, %s",
280 	    private != pk_false ? gettext("private") : gettext("public"),
281 	    modifiable == B_TRUE ? gettext("modifiable") :
282 	    gettext("not modifiable"));
283 	for (i = 3; i <= 12; i++) {
284 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
285 		    attrs[i].ulValueLen != 0 &&
286 		    *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
287 			(void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
288 	}
289 	(void) fprintf(stdout, ")\n");
290 
291 free_display_prikey:
292 	for (i = 3; i < n_attrs; i++)
293 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
294 		    attrs[i].ulValueLen != 0)
295 			free(attrs[i].pValue);
296 	return (rv);
297 }
298 
299 /*
300  * Display public key.
301  */
302 static CK_RV
303 display_pubkey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
304 {
305 	CK_RV			rv = CKR_OK;
306 	static CK_BBOOL		private;
307 	static CK_BBOOL		modifiable;
308 	static CK_BBOOL		trusted;
309 	static CK_KEY_TYPE	key_type;
310 	CK_ULONG		key_size;
311 	CK_BYTE			*label = NULL;
312 	CK_ULONG		label_len = 0;
313 	CK_BYTE			*id = NULL;
314 	CK_ULONG		id_len = 0;
315 	CK_BYTE			*subject = NULL;
316 	CK_ULONG		subject_len = 0;
317 	CK_DATE			*start_date = NULL;
318 	CK_ULONG		start_date_len = 0;
319 	CK_DATE			*end_date = NULL;
320 	CK_ULONG		end_date_len = 0;
321 	CK_ATTRIBUTE		attrs[15] = {
322 		/* 0 to 3 */
323 		{ CKA_PRIVATE, &private, sizeof (private) },
324 		{ CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
325 		{ CKA_TRUSTED, &trusted, sizeof (trusted) },
326 		{ CKA_KEY_TYPE, &key_type, sizeof (key_type) },
327 		/* 4 to 9 */
328 		{ CKA_DERIVE, NULL, 0 },
329 		{ CKA_LOCAL, NULL, 0 },
330 		{ CKA_ENCRYPT, NULL, 0 },
331 		{ CKA_VERIFY, NULL, 0 },
332 		{ CKA_VERIFY_RECOVER, NULL, 0 },
333 		{ CKA_WRAP, NULL, 0 },
334 		/* 10 to 14 */
335 		{ CKA_LABEL, NULL, 0 },			/* optional */
336 		{ CKA_ID, NULL, 0 },			/* optional */
337 		{ CKA_SUBJECT, NULL, 0 },		/* optional */
338 		{ CKA_START_DATE, NULL, 0 },		/* optional */
339 		{ CKA_END_DATE, NULL, 0 }		/* optional */
340 		/* not displaying CKA_KEY_GEN_MECHANISM */
341 	    };
342 	CK_ULONG	n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
343 	int		i;
344 	char		*hex_id = NULL;
345 	int		hex_id_len = 0;
346 	char		*hex_subject = NULL;
347 	int		hex_subject_len = 0;
348 
349 	cryptodebug("inside display_pubkey");
350 
351 	/* Get the sizes of the attributes we need. */
352 	cryptodebug("calling C_GetAttributeValue for size info");
353 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
354 		cryptoerror(LOG_STDERR, gettext(
355 		    "Unable to get public key attribute sizes (%s)."),
356 		    pkcs11_strerror(rv));
357 		return (rv);
358 	}
359 
360 	/* Allocate memory for each variable-length attribute. */
361 	for (i = 4; i < n_attrs; i++) {
362 		if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
363 		    attrs[i].ulValueLen == 0) {
364 			cryptodebug("display_pubkey: *** should not happen");
365 			attrs[i].ulValueLen = 0;
366 			continue;
367 		}
368 		if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
369 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
370 			rv = CKR_HOST_MEMORY;
371 			goto free_display_pubkey;
372 		}
373 	}
374 
375 	/* Now really get the attributes. */
376 	cryptodebug("calling C_GetAttributeValue for attribute info");
377 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
378 		cryptoerror(LOG_STDERR, gettext(
379 		    "Unable to get public key attributes (%s)."),
380 		    pkcs11_strerror(rv));
381 		goto free_display_pubkey;
382 	}
383 
384 	/* Fill in all the optional temp variables. */
385 	i = 10;
386 	copy_attr_to_string(&(attrs[i++]), &label, &label_len);
387 	copy_attr_to_string(&(attrs[i++]), &id, &id_len);
388 	copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
389 	copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
390 	copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
391 
392 	/* Get the key size for the object. */
393 	key_size = get_key_size(sess, obj, key_type);
394 
395 	/* Display the object ... */
396 		/* ... the label and what it is (and key size in bits) ... */
397 	(void) fprintf(stdout, gettext("%d.  \"%.*s\" (%d-bit %s %s)\n"),
398 	    counter, label_len, label_len > 0 ? (char *)label :
399 	    gettext("<no label>"), key_size, keytype_str(key_type),
400 	    class_str(CKO_PUBLIC_KEY));
401 
402 		/* ... the id ... */
403 	if (id_len == (CK_ULONG)-1 || id_len == 0)
404 		(void) fprintf(stdout, gettext("\tId:  --\n"));
405 	else {
406 		hex_id_len = 3 * id_len + 1;
407 		if ((hex_id = malloc(hex_id_len)) == NULL) {
408 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
409 			rv = CKR_HOST_MEMORY;
410 			goto free_display_pubkey;
411 		}
412 		octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
413 		    "\n\t\t", "");
414 		(void) fprintf(stdout, gettext("\tId:  %s\n"), hex_id);
415 		free(hex_id);
416 	}
417 
418 		/* ... the subject name ... */
419 	if (subject_len == (CK_ULONG)-1 || subject_len == 0)
420 		(void) fprintf(stdout, gettext("\tSubject:  --\n"));
421 	else {
422 		hex_subject_len = 2 * subject_len + 1;	/* best guesstimate */
423 		if ((hex_subject = malloc(hex_subject_len)) == NULL) {
424 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
425 			rv = CKR_HOST_MEMORY;
426 			goto free_display_pubkey;
427 		}
428 		rdnseq_to_str(subject, subject_len, hex_subject,
429 		    hex_subject_len);
430 		(void) fprintf(stdout, gettext("\tSubject:  %.*s\n"),
431 		    hex_subject_len, hex_subject);
432 		free(hex_subject);
433 	}
434 
435 		/* ... the start date ... */
436 	if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
437 		(void) fprintf(stdout, gettext("\tStart Date:  --\n"));
438 	else
439 		(void) fprintf(stdout, gettext(
440 		    "\tStart Date:  %02.2s/%02.2s/%04.4s\n"),
441 		    start_date->month, start_date->day, start_date->year);
442 
443 		/* ... the end date ... */
444 	if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
445 		(void) fprintf(stdout, gettext("\tEnd Date:  --\n"));
446 	else
447 		(void) fprintf(stdout, gettext(
448 		    "\tEnd Date:  %02.2s/%02.2s/%04.4s\n"),
449 		    end_date->month, end_date->day, end_date->year);
450 
451 		/* ... and its capabilities */
452 	(void) fprintf(stdout, "\t(%s, %s, %s",
453 	    private == B_TRUE ? gettext("private") : gettext("public"),
454 	    modifiable == B_TRUE ? gettext("modifiable") :
455 	    gettext("not modifiable"),
456 	    trusted == B_TRUE ? gettext("trusted") : gettext("untrusted"));
457 	for (i = 4; i <= 9; i++) {
458 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
459 		    attrs[i].ulValueLen != 0 &&
460 		    *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
461 			(void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
462 	}
463 	(void) fprintf(stdout, ")\n");
464 
465 free_display_pubkey:
466 	for (i = 4; i < n_attrs; i++)
467 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
468 		    attrs[i].ulValueLen != 0)
469 			free(attrs[i].pValue);
470 	return (rv);
471 }
472 
473 /*
474  * Display secret key.
475  */
476 static CK_RV
477 display_seckey(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
478 {
479 	CK_RV			rv = CKR_OK;
480 	static CK_BBOOL		private;
481 	static CK_BBOOL		modifiable;
482 	static CK_KEY_TYPE	key_type;
483 	static CK_ULONG		key_size;
484 	CK_BYTE			*label = NULL;
485 	CK_ULONG		label_len = 0;
486 	CK_BYTE			*id = NULL;
487 	CK_ULONG		id_len = 0;
488 	CK_DATE			*start_date = NULL;
489 	CK_ULONG		start_date_len = 0;
490 	CK_DATE			*end_date = NULL;
491 	CK_ULONG		end_date_len = 0;
492 	CK_ATTRIBUTE		attrs[19] = {
493 		/* 0 to 2 */
494 		{ CKA_PRIVATE, &private, sizeof (private) },
495 		{ CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
496 		{ CKA_KEY_TYPE, &key_type, sizeof (key_type) },
497 		/* 3 to 14 */
498 		{ CKA_DERIVE, NULL, 0 },
499 		{ CKA_LOCAL, NULL, 0 },
500 		{ CKA_ENCRYPT, NULL, 0 },
501 		{ CKA_DECRYPT, NULL, 0 },
502 		{ CKA_SIGN, NULL, 0 },
503 		{ CKA_VERIFY, NULL, 0 },
504 		{ CKA_WRAP, NULL, 0 },
505 		{ CKA_UNWRAP, NULL, 0 },
506 		{ CKA_SENSITIVE, NULL, 0 },
507 		{ CKA_ALWAYS_SENSITIVE, NULL, 0 },
508 		{ CKA_EXTRACTABLE, NULL, 0 },
509 		{ CKA_NEVER_EXTRACTABLE, 0 },
510 		/* 15 to 18 */
511 		{ CKA_LABEL, NULL, 0 },			/* optional */
512 		{ CKA_ID, NULL, 0 },			/* optional */
513 		{ CKA_START_DATE, NULL, 0 },		/* optional */
514 		{ CKA_END_DATE, NULL, 0 }		/* optional */
515 		/* not displaying CKA_KEY_GEN_MECHANISM */
516 	    };
517 	CK_ULONG	n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
518 	int		i;
519 	char		*hex_id = NULL;
520 	int		hex_id_len = 0;
521 
522 	cryptodebug("inside display_seckey");
523 
524 	/* Get the sizes of the attributes we need. */
525 	cryptodebug("calling C_GetAttributeValue for size info");
526 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
527 		cryptoerror(LOG_STDERR, gettext(
528 		    "Unable to get secret key attribute sizes (%s)."),
529 		    pkcs11_strerror(rv));
530 		return (rv);
531 	}
532 
533 	/* Allocate memory for each variable-length attribute. */
534 	for (i = 3; i < n_attrs; i++) {
535 		if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
536 		    attrs[i].ulValueLen == 0) {
537 			cryptodebug("display_seckey: *** should not happen");
538 			attrs[i].ulValueLen = 0;
539 			continue;
540 		}
541 		if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
542 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
543 			rv = CKR_HOST_MEMORY;
544 			goto free_display_seckey;
545 		}
546 	}
547 
548 	/* Now really get the attributes. */
549 	cryptodebug("calling C_GetAttributeValue for attribute info");
550 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
551 		cryptoerror(LOG_STDERR, gettext(
552 		    "Unable to get secret key attributes (%s)."),
553 		    pkcs11_strerror(rv));
554 		goto free_display_seckey;
555 	}
556 
557 	/* Fill in all the optional temp variables. */
558 	i = 15;
559 	copy_attr_to_string(&(attrs[i++]), &label, &label_len);
560 	copy_attr_to_string(&(attrs[i++]), &id, &id_len);
561 	copy_attr_to_date(&(attrs[i++]), &start_date, &start_date_len);
562 	copy_attr_to_date(&(attrs[i++]), &end_date, &end_date_len);
563 
564 	/* Get the key size for the object. */
565 	key_size = get_key_size(sess, obj, key_type);
566 
567 	/* Display the object ... */
568 		/* ... the label and what it is (and key size in bytes) ... */
569 	(void) fprintf(stdout, gettext("%d.  \"%.*s\" (%d-bit %s %s)\n"),
570 	    counter, label_len, label_len > 0 ? (char *)label :
571 	    gettext("<no label>"), key_size, keytype_str(key_type),
572 	    class_str(CKO_SECRET_KEY));
573 
574 		/* ... the id ... */
575 	if (id_len == (CK_ULONG)-1 || id_len == 0)
576 		(void) fprintf(stdout, gettext("\tId:  --\n"));
577 	else {
578 		hex_id_len = 3 * id_len + 1;
579 		if ((hex_id = malloc(hex_id_len)) == NULL) {
580 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
581 			rv = CKR_HOST_MEMORY;
582 			goto free_display_seckey;
583 		}
584 		octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
585 		    "\n\t\t", "");
586 		(void) fprintf(stdout, gettext("\tId:  %s\n"), hex_id);
587 		free(hex_id);
588 	}
589 
590 		/* ... the start date ... */
591 	if (start_date_len == (CK_ULONG)-1 || start_date_len == 0)
592 		(void) fprintf(stdout, gettext("\tStart Date:  --\n"));
593 	else
594 		(void) fprintf(stdout, gettext(
595 		    "\tStart Date:  %02.2s/%02.2s/%04.4s\n"),
596 		    start_date->month, start_date->day, start_date->year);
597 
598 		/* ... the end date ... */
599 	if (end_date_len == (CK_ULONG)-1 || end_date_len == 0)
600 		(void) fprintf(stdout, gettext("\tEnd Date:  --\n"));
601 	else
602 		(void) fprintf(stdout, gettext(
603 		    "\tEnd Date:  %02.2s/%02.2s/%04.4s\n"),
604 		    end_date->month, end_date->day, end_date->year);
605 
606 		/* ... and its capabilities */
607 	(void) fprintf(stdout, "\t(%s, %s",
608 	    private == B_TRUE ? gettext("private") : gettext("public"),
609 	    modifiable == B_TRUE ? gettext("modifiable") :
610 	    gettext("not modifiable"));
611 	for (i = 3; i <= 14; i++) {
612 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
613 		    attrs[i].ulValueLen != 0 &&
614 		    *((CK_BBOOL *)(attrs[i].pValue)) == B_TRUE)
615 			(void) fprintf(stdout, ", %s", attr_str(attrs[i].type));
616 	}
617 	(void) fprintf(stdout, ")\n");
618 
619 free_display_seckey:
620 	for (i = 3; i < n_attrs; i++)
621 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
622 		    attrs[i].ulValueLen != 0)
623 			free(attrs[i].pValue);
624 	return (rv);
625 }
626 
627 /*
628  * Display certificate.
629  */
630 static CK_RV
631 display_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int counter)
632 {
633 	CK_RV			rv = CKR_OK;
634 	static CK_BBOOL		private;
635 	static CK_BBOOL		modifiable;
636 	static CK_BBOOL		trusted;
637 	CK_BYTE			*subject = NULL;
638 	CK_ULONG		subject_len = 0;
639 	CK_BYTE			*value = NULL;
640 	CK_ULONG		value_len = 0;
641 	CK_BYTE			*label = NULL;
642 	CK_ULONG		label_len = 0;
643 	CK_BYTE			*id = NULL;
644 	CK_ULONG		id_len = 0;
645 	CK_BYTE			*issuer = NULL;
646 	CK_ULONG		issuer_len = 0;
647 	CK_BYTE			*serial = NULL;
648 	CK_ULONG		serial_len = 0;
649 	CK_ATTRIBUTE		attrs[9] = {
650 		{ CKA_PRIVATE, &private, sizeof (private) },
651 		{ CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
652 		{ CKA_TRUSTED, &trusted, sizeof (trusted) },
653 		{ CKA_SUBJECT, NULL, 0 },		/* required */
654 		{ CKA_VALUE, NULL, 0 },			/* required */
655 		{ CKA_LABEL, NULL, 0 },			/* optional */
656 		{ CKA_ID, NULL, 0 },			/* optional */
657 		{ CKA_ISSUER, NULL, 0 },		/* optional */
658 		{ CKA_SERIAL_NUMBER, NULL, 0 }		/* optional */
659 	    };
660 	CK_ULONG	n_attrs = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
661 	int		i;
662 	char		*hex_id = NULL;
663 	int		hex_id_len = 0;
664 	char		*hex_subject = NULL;
665 	int		hex_subject_len = 0;
666 	char		*hex_issuer = NULL;
667 	int		hex_issuer_len = 0;
668 	char		*hex_serial = NULL;
669 	int		hex_serial_len = NULL;
670 	uint32_t	serial_value = 0;
671 	char		*hex_value = NULL;
672 	int		hex_value_len = 0;
673 
674 	cryptodebug("inside display_cert");
675 
676 	/* Get the sizes of the attributes we need. */
677 	cryptodebug("calling C_GetAttributeValue for size info");
678 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
679 		cryptoerror(LOG_STDERR, gettext(
680 		    "Unable to get certificate attribute sizes (%s)."),
681 		    pkcs11_strerror(rv));
682 		return (rv);
683 	}
684 
685 	/* Allocate memory for each variable-length attribute. */
686 	for (i = 3; i < n_attrs; i++) {
687 		if (attrs[i].ulValueLen == (CK_ULONG)-1 ||
688 		    attrs[i].ulValueLen == 0) {
689 			cryptodebug("display_cert: *** should not happen");
690 			attrs[i].ulValueLen = 0;
691 			continue;
692 		}
693 		if ((attrs[i].pValue = malloc(attrs[i].ulValueLen)) == NULL) {
694 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
695 			rv = CKR_HOST_MEMORY;
696 			goto free_display_cert;
697 		}
698 	}
699 
700 	/* Now really get the attributes. */
701 	cryptodebug("calling C_GetAttributeValue for attribute info");
702 	if ((rv = C_GetAttributeValue(sess, obj, attrs, n_attrs)) != CKR_OK) {
703 		cryptoerror(LOG_STDERR, gettext(
704 		    "Unable to get certificate attributes (%s)."),
705 		    pkcs11_strerror(rv));
706 		goto free_display_cert;
707 	}
708 
709 	/*
710 	 * Fill in all the temp variables.  Subject and value are required.
711 	 * The rest are optional.
712 	 */
713 	i = 3;
714 	copy_attr_to_string(&(attrs[i++]), &subject, &subject_len);
715 	copy_attr_to_string(&(attrs[i++]), &value, &value_len);
716 	copy_attr_to_string(&(attrs[i++]), &label, &label_len);
717 	copy_attr_to_string(&(attrs[i++]), &id, &id_len);
718 	copy_attr_to_string(&(attrs[i++]), &issuer, &issuer_len);
719 	copy_attr_to_string(&(attrs[i++]), &serial, &serial_len);
720 
721 	/* Display the object ... */
722 		/* ... the label and what it is ... */
723 	(void) fprintf(stdout, gettext("%d.  \"%.*s\" (%s %s)\n"),
724 	    counter, label_len, label_len > 0 ? (char *)label :
725 	    gettext("<no label>"), "X.509", class_str(CKO_CERTIFICATE));
726 
727 		/* ... its capabilities ... */
728 	(void) fprintf(stdout, gettext("\t(%s, %s, %s)\n"),
729 	    private == B_TRUE ? gettext("private") : gettext("public"),
730 	    modifiable == B_TRUE ? gettext("modifiable") :
731 	    gettext("not modifiable"),
732 	    trusted == B_TRUE ? gettext("trusted") : gettext("untrusted"));
733 
734 		/* ... the id ... */
735 	if (id_len == (CK_ULONG)-1 || id_len == 0)
736 		(void) fprintf(stdout, gettext("\tId:  --\n"));
737 	else {
738 		hex_id_len = 3 * id_len + 1;
739 		if ((hex_id = malloc(hex_id_len)) == NULL) {
740 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
741 			rv = CKR_HOST_MEMORY;
742 			goto free_display_cert;
743 		}
744 		octetify(id, id_len, hex_id, hex_id_len, B_FALSE, B_FALSE, 60,
745 		    "\n\t\t", "");
746 		(void) fprintf(stdout, gettext("\tId:  %s\n"), hex_id);
747 		free(hex_id);
748 	}
749 
750 		/* ... the subject name ... */
751 	if (subject_len == (CK_ULONG)-1 || subject_len == 0)
752 		(void) fprintf(stdout, gettext("\tSubject:  --\n"));
753 	else {
754 		hex_subject_len = 2 * subject_len + 1;	/* best guesstimate */
755 		if ((hex_subject = malloc(hex_subject_len)) == NULL) {
756 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
757 			rv = CKR_HOST_MEMORY;
758 			goto free_display_cert;
759 		}
760 		rdnseq_to_str(subject, subject_len, hex_subject,
761 		    hex_subject_len);
762 		(void) fprintf(stdout, gettext("\tSubject:  %.*s\n"),
763 		    hex_subject_len, hex_subject);
764 		free(hex_subject);
765 	}
766 
767 		/* ... the issuer name ... */
768 	if (issuer_len == (CK_ULONG)-1 || issuer_len == 0)
769 		(void) fprintf(stdout, gettext("\tIssuer:  --\n"));
770 	else {
771 		hex_issuer_len = 2 * issuer_len + 1;	/* best guesstimate */
772 		if ((hex_issuer = malloc(hex_issuer_len)) == NULL) {
773 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
774 			rv = CKR_HOST_MEMORY;
775 			goto free_display_cert;
776 		}
777 		rdnseq_to_str(issuer, issuer_len, hex_issuer, hex_issuer_len);
778 		(void) fprintf(stdout, gettext("\tIssuer:  %.*s\n"),
779 		    hex_issuer_len, hex_issuer);
780 		free(hex_issuer);
781 	}
782 
783 		/* ... the serial number ... */
784 	if (serial_len == (CK_ULONG)-1 || serial_len == 0)
785 		(void) fprintf(stdout, gettext("\tSerial:  --\n"));
786 	else {
787 		hex_serial_len = 3 * serial_len + 1;
788 		if ((hex_serial = malloc(hex_serial_len)) == NULL) {
789 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
790 			rv = CKR_HOST_MEMORY;
791 			goto free_display_cert;
792 		}
793 		octetify(serial, serial_len, hex_serial, hex_serial_len,
794 		    B_FALSE, B_FALSE, 60, "\n\t\t", "");
795 		if (serial_len > 4)
796 			(void) fprintf(stdout, gettext("\tSerial:  %s\n"),
797 			    hex_serial);
798 		else {
799 			for (i = 0; i < serial_len; i++) {
800 				serial_value <<= 8;
801 				serial_value |= (serial[i] & 0xff);
802 			}
803 			(void) fprintf(stdout, gettext("\tSerial:  %s (%d)\n"),
804 			    hex_serial, serial_value);
805 		}
806 		free(hex_serial);
807 	}
808 
809 		/* ... and the value */
810 	if (value_len == (CK_ULONG)-1 || value_len == 0)
811 		(void) fprintf(stdout, gettext("\tValue:  --\n"));
812 	else {
813 		hex_value_len = 3 * value_len + 1;
814 		if ((hex_value = malloc(hex_value_len)) == NULL) {
815 			cryptoerror(LOG_STDERR, "%s.", strerror(errno));
816 			rv = CKR_HOST_MEMORY;
817 			goto free_display_cert;
818 		}
819 		octetify(value, value_len, hex_value, hex_value_len,
820 		    B_FALSE, B_FALSE, 60, "\n\t\t", "");
821 		(void) fprintf(stdout, gettext("\tValue:  %s\n"), hex_value);
822 		free(hex_value);
823 	}
824 
825 free_display_cert:
826 	for (i = 3; i < n_attrs; i++)
827 		if (attrs[i].ulValueLen != (CK_ULONG)-1 &&
828 		    attrs[i].ulValueLen != 0)
829 			free(attrs[i].pValue);
830 	return (rv);
831 }
832 
833 /*
834  * List token object.
835  */
836 int
837 pk_list(int argc, char *argv[])
838 {
839 	int			opt;
840 	extern int		optind_av;
841 	extern char		*optarg_av;
842 	char			*token_spec = NULL;
843 	char			*token_name = NULL;
844 	char			*manuf_id = NULL;
845 	char			*serial_no = NULL;
846 	char			*type_spec = NULL;
847 	char			full_name[FULL_NAME_LEN];
848 	boolean_t		public_objs = B_FALSE;
849 	boolean_t		private_objs = B_FALSE;
850 	CK_BYTE			*list_label = NULL;
851 	int			obj_type = 0x00;
852 	CK_SLOT_ID		slot_id;
853 	CK_FLAGS		pin_state;
854 	CK_UTF8CHAR_PTR		pin = NULL;
855 	CK_ULONG		pinlen = 0;
856 	CK_SESSION_HANDLE	sess;
857 	CK_OBJECT_HANDLE	*objs;
858 	CK_ULONG		num_objs;
859 	CK_RV			rv = CKR_OK;
860 	int			i;
861 	static CK_OBJECT_CLASS	objclass;
862 	CK_ATTRIBUTE		class_attr =
863 		{ CKA_CLASS, &objclass, sizeof (objclass) };
864 
865 	cryptodebug("inside pk_list");
866 
867 	/* Parse command line options.  Do NOT i18n/l10n. */
868 	while ((opt = getopt_av(argc, argv,
869 	    "T:(token)y:(objtype)l:(label)")) != EOF) {
870 		switch (opt) {
871 		case 'T':	/* token specifier */
872 			if (token_spec)
873 				return (PK_ERR_USAGE);
874 			token_spec = optarg_av;
875 			break;
876 		case 'y':	/* object type:  public, private, both */
877 			if (type_spec)
878 				return (PK_ERR_USAGE);
879 			type_spec = optarg_av;
880 			break;
881 		case 'l':	/* object with specific label */
882 			if (list_label)
883 				return (PK_ERR_USAGE);
884 			list_label = (CK_BYTE *)optarg_av;
885 			break;
886 		default:
887 			return (PK_ERR_USAGE);
888 			break;
889 		}
890 	}
891 
892 	/* If no token is specified, default is to use softtoken. */
893 	if (token_spec == NULL) {
894 		token_name = SOFT_TOKEN_LABEL;
895 		manuf_id = SOFT_MANUFACTURER_ID;
896 		serial_no = SOFT_TOKEN_SERIAL;
897 	} else {
898 		/*
899 		 * Parse token specifier into token_name, manuf_id, serial_no.
900 		 * Token_name is required; manuf_id and serial_no are optional.
901 		 */
902 		if (parse_token_spec(token_spec, &token_name, &manuf_id,
903 		    &serial_no) < 0)
904 			return (PK_ERR_USAGE);
905 	}
906 
907 	/* If no object type specified, default is public objects. */
908 	if (!type_spec) {
909 		public_objs = B_TRUE;
910 	} else {
911 		/*
912 		 * Otherwise, the object type must be "public", "private",
913 		 * or "both".
914 		 */
915 		if (strcmp(type_spec, "private") == 0) {
916 			private_objs = B_TRUE;
917 		} else if (strcmp(type_spec, "public") == 0) {
918 			public_objs = B_TRUE;
919 		} else if (strcmp(type_spec, "both") == 0) {
920 			private_objs = B_TRUE;
921 			public_objs = B_TRUE;
922 		} else
923 			return (PK_ERR_USAGE);
924 	}
925 
926 	if (private_objs)
927 		obj_type |= PK_PRIVATE_OBJ;
928 	if (public_objs)
929 		obj_type |= PK_PUBLIC_OBJ;
930 
931 	/* No additional args allowed. */
932 	argc -= optind_av;
933 	argv += optind_av;
934 	if (argc)
935 		return (PK_ERR_USAGE);
936 	/* Done parsing command line options. */
937 
938 	full_token_name(token_name, manuf_id, serial_no, full_name);
939 
940 	/* Find the slot with token. */
941 	if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
942 	    &pin_state)) != CKR_OK) {
943 		cryptoerror(LOG_STDERR, gettext(
944 		    "Unable to find token %s (%s)."), full_name,
945 		    pkcs11_strerror(rv));
946 		return (PK_ERR_PK11);
947 	}
948 
949 	/* If private objects are to be listed, user must be logged in. */
950 	if (private_objs) {
951 		/* Get the user's PIN. */
952 		if ((rv = get_pin(gettext("Enter token passphrase:"), NULL,
953 		    &pin, &pinlen)) != CKR_OK) {
954 			cryptoerror(LOG_STDERR,
955 			    gettext("Unable to get token passphrase (%s)."),
956 			    pkcs11_strerror(rv));
957 			quick_finish(NULL);
958 			return (PK_ERR_PK11);
959 		}
960 
961 		/* Logging in user R/O into the token is sufficient. */
962 		cryptodebug("logging in with readonly session");
963 		if ((rv = quick_start(slot_id, 0, pin, pinlen, &sess)) !=
964 		    CKR_OK) {
965 			cryptoerror(LOG_STDERR,
966 			    gettext("Unable to log into token (%s)."),
967 			    pkcs11_strerror(rv));
968 			quick_finish(sess);
969 			return (PK_ERR_PK11);
970 		}
971 	/* Otherwise, just create a session. */
972 	} else {
973 		cryptodebug("opening a readonly session");
974 		if ((rv = open_sess(slot_id, 0, &sess)) != CKR_OK) {
975 			cryptoerror(LOG_STDERR,
976 			    gettext("Unable to open token session (%s)."),
977 			    pkcs11_strerror(rv));
978 			quick_finish(sess);
979 			return (PK_ERR_PK11);
980 		}
981 	}
982 
983 	/* Find the object(s) with the given label and/or type. */
984 	if ((rv = find_objs(sess, obj_type, list_label, &objs, &num_objs)) !=
985 	    CKR_OK) {
986 		cryptoerror(LOG_STDERR, gettext(
987 		    "Unable to find token objects (%s)."), pkcs11_strerror(rv));
988 		quick_finish(sess);
989 		return (PK_ERR_PK11);
990 	}
991 
992 	if (num_objs == 0) {
993 		cryptoerror(LOG_STDERR, gettext("No objects found."));
994 		quick_finish(sess);
995 		return (0);
996 	}
997 
998 	/* List the objects found. */
999 	for (i = 0; i < num_objs; i++) {
1000 		/* Get object class first, then decide what is next. */
1001 		cryptodebug("calling C_GetAttributeValue for object class");
1002 		if ((rv = C_GetAttributeValue(sess, objs[i], &class_attr, 1))
1003 		    != CKR_OK) {
1004 			cryptoerror(LOG_STDERR, gettext(
1005 			    "Unable to get object #%d class attribute (%s)."),
1006 			    i+1, pkcs11_strerror(rv));
1007 			continue;
1008 		}
1009 
1010 		/* Display based on the type of object. */
1011 		switch (objclass) {
1012 		case CKO_CERTIFICATE:
1013 			if ((rv = display_cert(sess, objs[i], i+1)) != CKR_OK)
1014 				cryptoerror(LOG_STDERR,
1015 				    gettext("Unable to display certificate."));
1016 			break;
1017 		case CKO_PUBLIC_KEY:
1018 			if ((rv = display_pubkey(sess, objs[i], i+1)) != CKR_OK)
1019 				cryptoerror(LOG_STDERR,
1020 				    gettext("Unable to display public key."));
1021 			break;
1022 		case CKO_PRIVATE_KEY:
1023 			if ((rv = display_prikey(sess, objs[i], i+1)) != CKR_OK)
1024 				cryptoerror(LOG_STDERR,
1025 				    gettext("Unable to display private key."));
1026 			break;
1027 		case CKO_SECRET_KEY:
1028 			if ((rv = display_seckey(sess, objs[i], i+1)) != CKR_OK)
1029 				cryptoerror(LOG_STDERR,
1030 				    gettext("Unable to display secret key."));
1031 			break;
1032 		case CKO_DATA:
1033 			cryptoerror(LOG_STDERR,
1034 			    gettext("Data object display not implemented."));
1035 			break;
1036 		default:
1037 			cryptoerror(LOG_STDERR, gettext(
1038 			    "Unknown token object class (0x%02x)."), objclass);
1039 			break;
1040 		}
1041 	}
1042 
1043 	/* Clean up. */
1044 	quick_finish(sess);
1045 	return (0);
1046 }
1047