xref: /illumos-gate/usr/src/cmd/cmd-crypto/digest/digest.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * digest.c
28  *
29  * Implements digest(1) and mac(1) commands
30  * If command name is mac, performs mac operation
31  * else perform digest operation
32  *
33  * See the man pages for digest and mac for details on
34  * how these commands work.
35  */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <ctype.h>
42 #include <strings.h>
43 #include <libintl.h>
44 #include <libgen.h>
45 #include <locale.h>
46 #include <errno.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <security/cryptoki.h>
50 #include <limits.h>
51 #include <cryptoutil.h>
52 #include <kmfapi.h>
53 
54 #define	BUFFERSIZE	(4096)		/* Buffer size for reading file */
55 
56 /*
57  * RESULTLEN - large enough size in bytes to hold result for
58  * digest and mac results for all mechanisms
59  */
60 #define	RESULTLEN	(512)
61 
62 /*
63  * Exit Status codes
64  */
65 #ifndef	EXIT_SUCCESS
66 #define	EXIT_SUCCESS	0	/* No errors */
67 #define	EXIT_FAILURE	1	/* All errors except usage */
68 #endif /* EXIT_SUCCESS */
69 
70 #define	EXIT_USAGE	2	/* usage/syntax error */
71 
72 #define	MAC_NAME	"mac"		/* name of mac command */
73 #define	MAC_OPTIONS	"lva:k:T:K:"	/* for getopt */
74 #define	DIGEST_NAME	"digest"	/* name of digest command */
75 #define	DIGEST_OPTIONS	"lva:"		/* for getopt */
76 
77 /* Saved command line options */
78 static boolean_t vflag = B_FALSE;	/* -v (verbose) flag, optional */
79 static boolean_t aflag = B_FALSE;	/* -a <algorithm> flag, required */
80 static boolean_t lflag = B_FALSE;	/* -l flag, for mac and digest */
81 static boolean_t kflag = B_FALSE;	/* -k keyfile */
82 static boolean_t Tflag = B_FALSE;	/* -T token_spec */
83 static boolean_t Kflag = B_FALSE;	/* -K key_label */
84 
85 static char *keyfile = NULL;	 /* name of file containing key value */
86 static char *token_label = NULL; /* tokensSpec: tokenName[:manufId[:serial]] */
87 static char *key_label = NULL;	 /* PKCS#11 symmetric token key label */
88 
89 static CK_BYTE buf[BUFFERSIZE];
90 
91 struct mech_alias {
92 	CK_MECHANISM_TYPE type;
93 	char *alias;
94 	CK_ULONG keysize_min;
95 	CK_ULONG keysize_max;
96 	int keysize_unit;
97 	boolean_t available;
98 };
99 
100 #define	MECH_ALIASES_COUNT 11
101 
102 static struct mech_alias mech_aliases[] = {
103 	{ CKM_SHA_1, "sha1", ULONG_MAX, 0L, 8, B_FALSE },
104 	{ CKM_MD5, "md5", ULONG_MAX, 0L, 8, B_FALSE },
105 	{ CKM_DES_MAC, "des_mac", ULONG_MAX, 0L, 8, B_FALSE },
106 	{ CKM_SHA_1_HMAC, "sha1_hmac", ULONG_MAX, 0L, 8, B_FALSE },
107 	{ CKM_MD5_HMAC, "md5_hmac", ULONG_MAX, 0L, 8, B_FALSE },
108 	{ CKM_SHA256, "sha256", ULONG_MAX, 0L, 8, B_FALSE },
109 	{ CKM_SHA384, "sha384", ULONG_MAX, 0L, 8, B_FALSE },
110 	{ CKM_SHA512, "sha512", ULONG_MAX, 0L, 8, B_FALSE },
111 	{ CKM_SHA256_HMAC, "sha256_hmac", ULONG_MAX, 0L, 8, B_FALSE },
112 	{ CKM_SHA384_HMAC, "sha384_hmac", ULONG_MAX, 0L, 8, B_FALSE },
113 	{ CKM_SHA512_HMAC, "sha512_hmac", ULONG_MAX, 0L, 8, B_FALSE }
114 };
115 
116 static CK_BBOOL true = TRUE;
117 
118 static void usage(boolean_t mac_cmd);
119 static int execute_cmd(char *algo_str, int filecount,
120 	char **filelist, boolean_t mac_cmd);
121 static CK_RV do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
122 	int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature,
123 	CK_ULONG_PTR psignaturelen);
124 static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
125 	int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen);
126 
127 int
128 main(int argc, char **argv)
129 {
130 	extern char *optarg;
131 	extern int optind;
132 	int errflag = 0;	/* We had an optstr parse error */
133 	char c;			/* current getopts flag */
134 	char *algo_str;		/* mechanism/algorithm string */
135 	int filecount;
136 	boolean_t mac_cmd;	/* if TRUE, do mac, else do digest */
137 	char *optstr;
138 	char **filelist;	/* list of files */
139 	char *cmdname = NULL;	/* name of command */
140 
141 	(void) setlocale(LC_ALL, "");
142 #if !defined(TEXT_DOMAIN)	/* Should be defiend by cc -D */
143 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
144 #endif
145 	(void) textdomain(TEXT_DOMAIN);
146 
147 	/*
148 	 * Based on command name, determine
149 	 * type of command. mac is mac
150 	 * everything else is digest.
151 	 */
152 	cmdname = basename(argv[0]);
153 
154 	cryptodebug_init(cmdname);
155 
156 	if (strcmp(cmdname, MAC_NAME) == 0)
157 		mac_cmd = B_TRUE;
158 	else if (strcmp(cmdname, DIGEST_NAME) == 0)
159 		mac_cmd = B_FALSE;
160 	else {
161 		cryptoerror(LOG_STDERR, gettext(
162 		    "command name must be either digest or mac\n"));
163 		exit(EXIT_USAGE);
164 	}
165 
166 	if (mac_cmd) {
167 		optstr = MAC_OPTIONS;
168 	} else {
169 		optstr = DIGEST_OPTIONS;
170 	}
171 
172 	/* Parse command line arguments */
173 	while (!errflag && (c = getopt(argc, argv, optstr)) != -1) {
174 
175 		switch (c) {
176 		case 'v':
177 			vflag = B_TRUE;
178 			break;
179 		case 'a':
180 			aflag = B_TRUE;
181 			algo_str = optarg;
182 			break;
183 		case 'k':
184 			kflag = B_TRUE;
185 			keyfile = optarg;
186 			break;
187 		case 'l':
188 			lflag = B_TRUE;
189 			break;
190 		case 'T':
191 			Tflag = B_TRUE;
192 			token_label = optarg;
193 			break;
194 		case 'K':
195 			Kflag = B_TRUE;
196 			key_label = optarg;
197 			break;
198 		default:
199 			errflag++;
200 		}
201 	}
202 
203 	filecount = argc - optind;
204 	if (errflag || (!aflag && !lflag) || (lflag && argc > 2) ||
205 	    (kflag && Kflag) || (Tflag && !Kflag) || filecount < 0) {
206 		usage(mac_cmd);
207 		exit(EXIT_USAGE);
208 	}
209 
210 	if (filecount == 0) {
211 		filelist = NULL;
212 	} else {
213 		filelist = &argv[optind];
214 	}
215 
216 	return (execute_cmd(algo_str, filecount, filelist, mac_cmd));
217 }
218 
219 /*
220  * usage message for digest/mac
221  */
222 static void
223 usage(boolean_t mac_cmd)
224 {
225 	(void) fprintf(stderr, gettext("Usage:\n"));
226 	if (mac_cmd) {
227 		(void) fprintf(stderr, gettext("  mac -l\n"));
228 		(void) fprintf(stderr, gettext("  mac [-v] -a <algorithm> "
229 		    "[-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
230 		    "[file...]\n"));
231 	} else {
232 		(void) fprintf(stderr, gettext("  digest -l | [-v] "
233 		    "-a <algorithm> [file...]\n"));
234 	}
235 }
236 
237 /*
238  * Print out list of available algorithms.
239  */
240 static void
241 algorithm_list(boolean_t mac_cmd)
242 {
243 	int mech;
244 
245 	if (mac_cmd)
246 		(void) printf(gettext("Algorithm       Keysize:  Min   "
247 		    "Max (bits)\n"
248 		    "------------------------------------------\n"));
249 
250 	for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) {
251 
252 		if (mech_aliases[mech].available == B_FALSE)
253 			continue;
254 
255 		if (mac_cmd) {
256 			(void) printf("%-15s", mech_aliases[mech].alias);
257 
258 			if (mech_aliases[mech].keysize_min != ULONG_MAX &&
259 			    mech_aliases[mech].keysize_max != 0)
260 				(void) printf("         %5lu %5lu\n",
261 				    (mech_aliases[mech].keysize_min *
262 				    mech_aliases[mech].keysize_unit),
263 				    (mech_aliases[mech].keysize_max *
264 				    mech_aliases[mech].keysize_unit));
265 			else
266 				(void) printf("\n");
267 
268 		} else
269 			(void) printf("%s\n", mech_aliases[mech].alias);
270 
271 	}
272 }
273 
274 static int
275 get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype,
276     char *keylabel, CK_BYTE *password, int password_len,
277     CK_OBJECT_HANDLE *keyobj)
278 {
279 	CK_RV rv;
280 	CK_ATTRIBUTE pTmpl[10];
281 	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
282 	CK_BBOOL true = 1;
283 	CK_BBOOL is_token = 1;
284 	CK_ULONG key_obj_count = 1;
285 	int i;
286 	CK_KEY_TYPE ckKeyType = keytype;
287 
288 
289 	rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password,
290 	    password_len);
291 	if (rv != CKR_OK) {
292 		(void) fprintf(stderr, "Cannot login to the token."
293 		    " error = %s\n", pkcs11_strerror(rv));
294 		return (-1);
295 	}
296 
297 	i = 0;
298 	pTmpl[i].type = CKA_TOKEN;
299 	pTmpl[i].pValue = &is_token;
300 	pTmpl[i].ulValueLen = sizeof (CK_BBOOL);
301 	i++;
302 
303 	pTmpl[i].type = CKA_CLASS;
304 	pTmpl[i].pValue = &class;
305 	pTmpl[i].ulValueLen = sizeof (class);
306 	i++;
307 
308 	pTmpl[i].type = CKA_LABEL;
309 	pTmpl[i].pValue = keylabel;
310 	pTmpl[i].ulValueLen = strlen(keylabel);
311 	i++;
312 
313 	pTmpl[i].type = CKA_KEY_TYPE;
314 	pTmpl[i].pValue = &ckKeyType;
315 	pTmpl[i].ulValueLen = sizeof (ckKeyType);
316 	i++;
317 
318 	pTmpl[i].type = CKA_PRIVATE;
319 	pTmpl[i].pValue = &true;
320 	pTmpl[i].ulValueLen = sizeof (true);
321 	i++;
322 
323 	rv = C_FindObjectsInit(hSession, pTmpl, i);
324 	if (rv != CKR_OK) {
325 		goto out;
326 	}
327 
328 	rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count);
329 	(void) C_FindObjectsFinal(hSession);
330 
331 out:
332 	if (rv != CKR_OK) {
333 		(void) fprintf(stderr,
334 		    "Cannot retrieve key object. error = %s\n",
335 		    pkcs11_strerror(rv));
336 		return (-1);
337 	}
338 
339 	if (key_obj_count == 0) {
340 		(void) fprintf(stderr, "Cannot find the key object.\n");
341 		return (-1);
342 	}
343 
344 	return (0);
345 }
346 
347 
348 /*
349  * Execute the command.
350  *   algo_str - name of algorithm
351  *   filecount - no. of files to process, if 0, use stdin
352  *   filelist - list of files
353  *   mac_cmd - if true do mac else do digest
354  */
355 static int
356 execute_cmd(char *algo_str, int filecount, char **filelist, boolean_t mac_cmd)
357 {
358 	int fd;
359 	char *filename = NULL;
360 	CK_RV rv;
361 	CK_ULONG slotcount;
362 	CK_SLOT_ID slotID;
363 	CK_SLOT_ID_PTR pSlotList = NULL;
364 	CK_MECHANISM_TYPE mech_type;
365 	CK_MECHANISM_INFO info;
366 	CK_MECHANISM mech;
367 	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
368 	CK_BYTE_PTR resultbuf = NULL;
369 	CK_ULONG resultlen;
370 	CK_BYTE_PTR	pkeydata = NULL;
371 	CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0;
372 	size_t keylen = 0;		/* key length */
373 	char *resultstr = NULL;	/* result in hex string */
374 	int resultstrlen;	/* result string length */
375 	int i;
376 	int exitcode = EXIT_SUCCESS;		/* return code */
377 	int slot, mek;			/* index variables */
378 	int mech_match = 0;
379 	CK_BYTE		salt[CK_PKCS5_PBKD2_SALT_SIZE];
380 	CK_ULONG	keysize;
381 	CK_ULONG	iterations = CK_PKCS5_PBKD2_ITERATIONS;
382 	CK_KEY_TYPE keytype;
383 	KMF_RETURN kmfrv;
384 	CK_SLOT_ID token_slot_id;
385 
386 	if (aflag) {
387 		/*
388 		 * Determine if algorithm/mechanism is valid
389 		 */
390 		for (mech_match = 0; mech_match < MECH_ALIASES_COUNT;
391 		    mech_match++) {
392 			if (strcmp(algo_str,
393 			    mech_aliases[mech_match].alias) == 0) {
394 				mech_type = mech_aliases[mech_match].type;
395 				break;
396 			}
397 
398 		}
399 
400 		if (mech_match == MECH_ALIASES_COUNT) {
401 			cryptoerror(LOG_STDERR,
402 			    gettext("unknown algorithm -- %s"), algo_str);
403 			return (EXIT_FAILURE);
404 		}
405 
406 		/* Get key to do a MAC operation */
407 		if (mac_cmd) {
408 			int status;
409 
410 			if (Kflag) {
411 				/* get the pin of the token */
412 				if (token_label == NULL ||
413 				    !strlen(token_label)) {
414 					token_label = pkcs11_default_token();
415 				}
416 
417 				status = pkcs11_get_pass(token_label,
418 				    (char **)&pkeydata, &keylen,
419 				    0, B_FALSE);
420 			} else if (keyfile != NULL) {
421 				/* get the key file */
422 				status = pkcs11_read_data(keyfile,
423 				    (void **)&pkeydata, &keylen);
424 			} else {
425 				/* get the key from input */
426 				status = pkcs11_get_pass(NULL,
427 				    (char **)&pkeydata, &keylen,
428 				    0, B_FALSE);
429 			}
430 
431 			if (status != 0 || keylen == 0 || pkeydata == NULL) {
432 				cryptoerror(LOG_STDERR,
433 				    (Kflag || (keyfile == NULL)) ?
434 				    gettext("invalid passphrase.") :
435 				    gettext("invalid key."));
436 				return (EXIT_FAILURE);
437 			}
438 		}
439 	}
440 
441 	/* Initialize, and get list of slots */
442 	rv = C_Initialize(NULL);
443 	if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
444 		cryptoerror(LOG_STDERR,
445 		    gettext("failed to initialize PKCS #11 framework: %s"),
446 		    pkcs11_strerror(rv));
447 		return (EXIT_FAILURE);
448 	}
449 
450 	/* Get slot count */
451 	rv = C_GetSlotList(0, NULL_PTR, &slotcount);
452 	if (rv != CKR_OK || slotcount == 0) {
453 		cryptoerror(LOG_STDERR, gettext(
454 		    "failed to find any cryptographic provider; "
455 		    "please check with your system administrator: %s"),
456 		    pkcs11_strerror(rv));
457 		exitcode = EXIT_FAILURE;
458 		goto cleanup;
459 	}
460 
461 	/* Found at least one slot, allocate memory for slot list */
462 	pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
463 	if (pSlotList == NULL_PTR) {
464 		int err = errno;
465 		cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
466 		    strerror(err));
467 		exitcode = EXIT_FAILURE;
468 		goto cleanup;
469 	}
470 
471 	/* Get the list of slots */
472 	if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) {
473 		cryptoerror(LOG_STDERR, gettext(
474 		    "failed to find any cryptographic provider; "
475 		    "please check with your system administrator: %s"),
476 		    pkcs11_strerror(rv));
477 		exitcode = EXIT_FAILURE;
478 		goto cleanup;
479 	}
480 
481 	/*
482 	 * Obtain list of algorithms if -l option was given
483 	 */
484 	if (lflag) {
485 
486 		for (slot = 0; slot < slotcount; slot++) {
487 
488 			/* Iterate through each mechanism */
489 			for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) {
490 				rv = C_GetMechanismInfo(pSlotList[slot],
491 				    mech_aliases[mek].type, &info);
492 
493 				/* Only check algorithms that can be used */
494 				if ((rv != CKR_OK) ||
495 				    (!mac_cmd && (info.flags & CKF_SIGN)) ||
496 				    (mac_cmd && (info.flags & CKF_DIGEST)))
497 					continue;
498 
499 				/*
500 				 * Set to minimum/maximum key sizes assuming
501 				 * the values available are not 0.
502 				 */
503 				if (info.ulMinKeySize && (info.ulMinKeySize <
504 				    mech_aliases[mek].keysize_min))
505 					mech_aliases[mek].keysize_min =
506 					    info.ulMinKeySize;
507 
508 				if (info.ulMaxKeySize && (info.ulMaxKeySize >
509 				    mech_aliases[mek].keysize_max))
510 					mech_aliases[mek].keysize_max =
511 					    info.ulMaxKeySize;
512 
513 				mech_aliases[mek].available = B_TRUE;
514 			}
515 
516 		}
517 
518 		algorithm_list(mac_cmd);
519 
520 		goto cleanup;
521 	}
522 
523 	/*
524 	 * Find a slot with matching mechanism
525 	 *
526 	 * If -K is specified, we find the slot id for the token first, then
527 	 * check if the slot supports the algorithm.
528 	 */
529 	i = 0;
530 	if (Kflag) {
531 		kmfrv = kmf_pk11_token_lookup(NULL, token_label,
532 		    &token_slot_id);
533 		if (kmfrv != KMF_OK) {
534 			cryptoerror(LOG_STDERR,
535 			    gettext("no matching PKCS#11 token"));
536 			exitcode = EXIT_FAILURE;
537 			goto cleanup;
538 		}
539 		rv = C_GetMechanismInfo(token_slot_id, mech_type, &info);
540 		if (rv == CKR_OK && (info.flags & CKF_SIGN))
541 			slotID = token_slot_id;
542 		else
543 			i = slotcount;
544 
545 	} else {
546 		for (i = 0; i < slotcount; i++) {
547 			slotID = pSlotList[i];
548 			rv = C_GetMechanismInfo(slotID, mech_type, &info);
549 			if (rv != CKR_OK) {
550 				continue; /* to the next slot */
551 			} else {
552 				if (mac_cmd) {
553 					/*
554 					 * Make sure the slot supports
555 					 * PKCS5 key generation if we
556 					 * will be using it later.
557 					 * We use it whenever the key
558 					 * is entered at command line.
559 					 */
560 					if ((info.flags & CKF_SIGN) &&
561 					    (keyfile == NULL)) {
562 						CK_MECHANISM_INFO kg_info;
563 						rv = C_GetMechanismInfo(slotID,
564 						    CKM_PKCS5_PBKD2, &kg_info);
565 						if (rv == CKR_OK)
566 							break;
567 					} else if (info.flags & CKF_SIGN) {
568 						break;
569 					}
570 				} else {
571 					if (info.flags & CKF_DIGEST)
572 						break;
573 				}
574 			}
575 		}
576 	}
577 
578 	/* Show error if no matching mechanism found */
579 	if (i == slotcount) {
580 		cryptoerror(LOG_STDERR,
581 		    gettext("no cryptographic provider was "
582 		    "found for this algorithm -- %s"), algo_str);
583 		exitcode = EXIT_FAILURE;
584 		goto cleanup;
585 	}
586 
587 	/* Mechanism is supported. Go ahead & open a session */
588 	rv = C_OpenSession(slotID, CKF_SERIAL_SESSION,
589 	    NULL_PTR, NULL, &hSession);
590 
591 	if (rv != CKR_OK) {
592 		cryptoerror(LOG_STDERR,
593 		    gettext("can not open PKCS#11 session: %s"),
594 		    pkcs11_strerror(rv));
595 		exitcode = EXIT_FAILURE;
596 		goto cleanup;
597 	}
598 
599 	/* Create a key object for mac operation */
600 	if (mac_cmd) {
601 		/*
602 		 * If we read keybytes from a file,
603 		 * do NOT process them with C_GenerateKey,
604 		 * treat them as raw keydata bytes and
605 		 * create a key object for them.
606 		 */
607 		if (keyfile) {
608 			/* XXX : why wasn't SUNW_C_KeyToObject used here? */
609 			CK_OBJECT_CLASS class = CKO_SECRET_KEY;
610 			CK_KEY_TYPE tmpl_keytype = CKK_GENERIC_SECRET;
611 			CK_BBOOL false = FALSE;
612 			int nattr = 0;
613 			CK_ATTRIBUTE template[5];
614 
615 			if (mech_type == CKM_DES_MAC) {
616 				tmpl_keytype = CKK_DES;
617 			}
618 			template[nattr].type = CKA_CLASS;
619 			template[nattr].pValue = &class;
620 			template[nattr].ulValueLen = sizeof (class);
621 			nattr++;
622 
623 			template[nattr].type = CKA_KEY_TYPE;
624 			template[nattr].pValue = &tmpl_keytype;
625 			template[nattr].ulValueLen = sizeof (tmpl_keytype);
626 			nattr++;
627 
628 			template[nattr].type = CKA_SIGN;
629 			template[nattr].pValue = &true;
630 			template[nattr].ulValueLen = sizeof (true);
631 			nattr++;
632 
633 			template[nattr].type = CKA_TOKEN;
634 			template[nattr].pValue = &false;
635 			template[nattr].ulValueLen = sizeof (false);
636 			nattr++;
637 
638 			template[nattr].type = CKA_VALUE;
639 			template[nattr].pValue = pkeydata;
640 			template[nattr].ulValueLen = keylen;
641 			nattr++;
642 
643 			rv = C_CreateObject(hSession, template, nattr, &key);
644 
645 		} else if (Kflag) {
646 
647 			if (mech_type == CKM_DES_MAC) {
648 				keytype = CKK_DES;
649 			} else {
650 				keytype = CKK_GENERIC_SECRET;
651 			}
652 
653 			rv = get_token_key(hSession, keytype, key_label,
654 			    pkeydata, keylen, &key);
655 			if (rv != CKR_OK) {
656 				exitcode = EXIT_FAILURE;
657 				goto cleanup;
658 			}
659 		} else {
660 			CK_KEY_TYPE keytype;
661 			if (mech_type == CKM_DES_MAC) {
662 				keytype = CKK_DES;
663 				keysize = 0;
664 			} else {
665 				keytype = CKK_GENERIC_SECRET;
666 				keysize = 16; /* 128 bits */
667 			}
668 			/*
669 			 * We use a fixed salt (0x0a, 0x0a, 0x0a ...)
670 			 * for creating the key so that the end user
671 			 * will be able to generate the same 'mac'
672 			 * using the same passphrase.
673 			 */
674 			(void) memset(salt, 0x0a, sizeof (salt));
675 			rv = pkcs11_PasswdToPBKD2Object(hSession,
676 			    (char *)pkeydata, (size_t)keylen, (void *)salt,
677 			    sizeof (salt), iterations, keytype, keysize,
678 			    CKF_SIGN, &key);
679 		}
680 
681 		if (rv != CKR_OK) {
682 			cryptoerror(LOG_STDERR,
683 			    gettext("unable to create key for crypto "
684 			    "operation: %s"), pkcs11_strerror(rv));
685 			exitcode = EXIT_FAILURE;
686 			goto cleanup;
687 		}
688 	}
689 
690 	/* Allocate a buffer to store result. */
691 	resultlen = RESULTLEN;
692 	if ((resultbuf = malloc(resultlen)) == NULL) {
693 		int err = errno;
694 		cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
695 		    strerror(err));
696 		exitcode = EXIT_FAILURE;
697 		goto cleanup;
698 	}
699 
700 	/* Allocate a buffer to store result string */
701 	resultstrlen = RESULTLEN;
702 	if ((resultstr = malloc(resultstrlen)) == NULL) {
703 		int err = errno;
704 		cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
705 		    strerror(err));
706 		exitcode = EXIT_FAILURE;
707 		goto cleanup;
708 	}
709 
710 	mech.mechanism = mech_type;
711 	mech.pParameter = NULL_PTR;
712 	mech.ulParameterLen = 0;
713 	exitcode = EXIT_SUCCESS;
714 	i = 0;
715 
716 	do {
717 		if (filecount > 0 && filelist != NULL) {
718 			filename = filelist[i];
719 			if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) ==
720 			    -1) {
721 				cryptoerror(LOG_STDERR, gettext(
722 				    "can not open input file %s\n"), filename);
723 				exitcode = EXIT_USAGE;
724 				continue;
725 			}
726 		} else {
727 			fd = 0; /* use stdin */
728 		}
729 
730 		/*
731 		 * Perform the operation
732 		 */
733 		if (mac_cmd) {
734 			rv = do_mac(hSession, &mech, fd, key, &resultbuf,
735 			    &resultlen);
736 		} else {
737 			rv = do_digest(hSession, &mech, fd, &resultbuf,
738 			    &resultlen);
739 		}
740 
741 		if (rv != CKR_OK) {
742 			cryptoerror(LOG_STDERR,
743 			    gettext("crypto operation failed for "
744 			    "file %s: %s\n"),
745 			    filename ? filename : "STDIN",
746 			    pkcs11_strerror(rv));
747 			exitcode = EXIT_FAILURE;
748 			continue;
749 		}
750 
751 		/* if result size has changed, allocate a bigger resulstr buf */
752 		if (resultlen != RESULTLEN) {
753 			resultstrlen = 2 * resultlen + 1;
754 			resultstr = realloc(resultstr, resultstrlen);
755 
756 			if (resultstr == NULL) {
757 				int err = errno;
758 				cryptoerror(LOG_STDERR,
759 				    gettext("realloc: %s\n"), strerror(err));
760 				exitcode =  EXIT_FAILURE;
761 				goto cleanup;
762 			}
763 		}
764 
765 		/* Output the result */
766 		tohexstr(resultbuf, resultlen, resultstr, resultstrlen);
767 
768 		/* Include mechanism name for verbose */
769 		if (vflag)
770 			(void) fprintf(stdout, "%s ", algo_str);
771 
772 		/* Include file name for multiple files, or if verbose */
773 		if (filecount > 1 || (vflag && filecount > 0)) {
774 			(void) fprintf(stdout, "(%s) = ", filename);
775 		}
776 
777 		(void) fprintf(stdout, "%s\n", resultstr);
778 		(void) close(fd);
779 
780 
781 	} while (++i < filecount);
782 
783 
784 	/* clear and free the key */
785 	if (mac_cmd) {
786 		(void) memset(pkeydata, 0, keylen);
787 		free(pkeydata);
788 		pkeydata = NULL;
789 	}
790 
791 cleanup:
792 	if (resultbuf != NULL) {
793 		free(resultbuf);
794 	}
795 
796 	if (resultstr != NULL) {
797 		free(resultstr);
798 	}
799 
800 	if (pSlotList != NULL) {
801 		free(pSlotList);
802 	}
803 
804 	if (!Kflag && key != (CK_OBJECT_HANDLE) 0) {
805 		(void) C_DestroyObject(hSession, key);
806 	}
807 
808 	if (hSession != CK_INVALID_HANDLE)
809 		(void) C_CloseSession(hSession);
810 
811 	(void) C_Finalize(NULL_PTR);
812 
813 	return (exitcode);
814 }
815 
816 /*
817  * do_digest - Compute digest of a file
818  *
819  *  hSession - session
820  *  pmech - ptr to mechanism to be used for digest
821  *  fd  - file descriptor
822  *  pdigest - buffer  where digest result is returned
823  *  pdigestlen - length of digest buffer on input,
824  *               length of result on output
825  */
826 static CK_RV
827 do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
828 	int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen)
829 {
830 	CK_RV rv;
831 	ssize_t nread;
832 	int saved_errno;
833 
834 	if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) {
835 		return (rv);
836 	}
837 
838 	while ((nread = read(fd, buf, sizeof (buf))) > 0) {
839 		/* Get the digest */
840 		rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread);
841 		if (rv != CKR_OK)
842 			return (rv);
843 	}
844 
845 	saved_errno = errno; /* for later use */
846 
847 	/*
848 	 * Perform the C_DigestFinal, even if there is a read error.
849 	 * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE
850 	 * next time it is called (for another file)
851 	 */
852 
853 	rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
854 
855 	/* result too big to fit? Allocate a bigger buffer */
856 	if (rv == CKR_BUFFER_TOO_SMALL) {
857 		*pdigest = realloc(*pdigest, *pdigestlen);
858 
859 		if (*pdigest == NULL_PTR) {
860 			int err = errno;
861 			cryptoerror(LOG_STDERR,
862 			    gettext("realloc: %s\n"), strerror(err));
863 			return (CKR_HOST_MEMORY);
864 		}
865 
866 		rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
867 	}
868 
869 
870 	/* There was a read error */
871 	if (nread == -1) {
872 		cryptoerror(LOG_STDERR, gettext(
873 		    "error reading file: %s"), strerror(saved_errno));
874 		return (CKR_GENERAL_ERROR);
875 	} else {
876 		return (rv);
877 	}
878 }
879 
880 /*
881  * do_mac - Compute mac of a file
882  *
883  *  hSession - session
884  *  pmech - ptr to mechanism to be used
885  *  fd  - file descriptor
886  *  key - key to be used
887  *  psignature - ptr buffer  where mac result is returned
888  *		returns new buf if current buf is small
889  *  psignaturelen - length of mac buffer on input,
890  *               length of result on output
891  */
892 static CK_RV
893 do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
894 	int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature,
895 	CK_ULONG_PTR psignaturelen)
896 {
897 	CK_RV rv;
898 	ssize_t nread;
899 	int saved_errno;
900 
901 	if ((rv = C_SignInit(hSession, pmech, key)) != CKR_OK) {
902 		return (rv);
903 	}
904 
905 	while ((nread = read(fd, buf, sizeof (buf))) > 0) {
906 		/* Get the MAC */
907 		rv = C_SignUpdate(hSession, buf, (CK_ULONG)nread);
908 		if (rv != CKR_OK)
909 			return (rv);
910 	}
911 
912 	saved_errno = errno; /* for later use */
913 
914 	/*
915 	 * Perform the C_SignFinal, even if there is a read error.
916 	 * Otherwise C_SignInit will return CKR_OPERATION_ACTIVE
917 	 * next time it is called (for another file)
918 	 */
919 
920 	rv = C_SignFinal(hSession, *psignature, psignaturelen);
921 
922 	/* result too big to fit? Allocate a bigger buffer */
923 	if (rv == CKR_BUFFER_TOO_SMALL) {
924 		*psignature = realloc(*psignature, *psignaturelen);
925 
926 		if (*psignature == NULL_PTR) {
927 			int err = errno;
928 			cryptoerror(LOG_STDERR,
929 			    gettext("realloc: %s\n"), strerror(err));
930 			return (CKR_HOST_MEMORY);
931 		}
932 
933 		rv = C_SignFinal(hSession, *psignature, psignaturelen);
934 	}
935 
936 	/* There was a read error */
937 	if (nread == -1) {
938 		cryptoerror(LOG_STDERR, gettext("error reading file: %s"),
939 		    strerror(saved_errno));
940 		return (CKR_GENERAL_ERROR);
941 	} else {
942 		return (rv);
943 	}
944 }
945