xref: /illumos-gate/usr/src/cmd/cmd-crypto/digest/digest.c (revision f03fb72c9f13560757b95b26631635b5d2a6d6c5)
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 2008 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 mac command */
75 #define	DIGEST_OPTIONS	"lva:"		/* for getopt */
76 
77 static boolean_t vflag = B_FALSE;	/* -v (verbose) flag, optional */
78 static boolean_t aflag = B_FALSE;	/* -a <algorithm> flag, required */
79 static boolean_t lflag = B_FALSE;	/* -l flag, for mac and digest */
80 static boolean_t kflag = B_FALSE;
81 static boolean_t Tflag = B_FALSE;
82 static boolean_t Kflag = B_FALSE;
83 
84 static char *keyfile = NULL;	/* name of keyfile */
85 static char *token_label = NULL;
86 static char *key_label = NULL;
87 
88 static CK_BYTE buf[BUFFERSIZE];
89 
90 struct mech_alias {
91 	CK_MECHANISM_TYPE type;
92 	char *alias;
93 	CK_ULONG keysize_min;
94 	CK_ULONG keysize_max;
95 	int keysize_unit;
96 	boolean_t available;
97 };
98 
99 #define	MECH_ALIASES_COUNT 11
100 
101 static struct mech_alias mech_aliases[] = {
102 	{ CKM_SHA_1, "sha1", ULONG_MAX, 0L, 8, B_FALSE },
103 	{ CKM_MD5, "md5", ULONG_MAX, 0L, 8, B_FALSE },
104 	{ CKM_DES_MAC, "des_mac", ULONG_MAX, 0L, 8, B_FALSE },
105 	{ CKM_SHA_1_HMAC, "sha1_hmac", ULONG_MAX, 0L, 8, B_FALSE },
106 	{ CKM_MD5_HMAC, "md5_hmac", ULONG_MAX, 0L, 8, B_FALSE },
107 	{ CKM_SHA256, "sha256", ULONG_MAX, 0L, 8, B_FALSE },
108 	{ CKM_SHA384, "sha384", ULONG_MAX, 0L, 8, B_FALSE },
109 	{ CKM_SHA512, "sha512", ULONG_MAX, 0L, 8, B_FALSE },
110 	{ CKM_SHA256_HMAC, "sha256_hmac", ULONG_MAX, 0L, 8, B_FALSE },
111 	{ CKM_SHA384_HMAC, "sha384_hmac", ULONG_MAX, 0L, 8, B_FALSE },
112 	{ CKM_SHA512_HMAC, "sha512_hmac", ULONG_MAX, 0L, 8, B_FALSE }
113 };
114 
115 static CK_BBOOL true = TRUE;
116 
117 static void usage(boolean_t mac_cmd);
118 static int execute_cmd(char *algo_str, int filecount,
119 	char **filelist, boolean_t mac_cmd);
120 static CK_RV do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
121 	int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature,
122 	CK_ULONG_PTR psignaturelen);
123 static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
124 	int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen);
125 
126 int
127 main(int argc, char **argv)
128 {
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 ? gettext("invalid passphrase.") :
434 				    gettext("invalid key."));
435 				return (EXIT_FAILURE);
436 			}
437 		}
438 	}
439 
440 	/* Initialize, and get list of slots */
441 	rv = C_Initialize(NULL);
442 	if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
443 		cryptoerror(LOG_STDERR,
444 		    gettext("failed to initialize PKCS #11 framework: %s"),
445 		    pkcs11_strerror(rv));
446 		return (EXIT_FAILURE);
447 	}
448 
449 	/* Get slot count */
450 	rv = C_GetSlotList(0, NULL_PTR, &slotcount);
451 	if (rv != CKR_OK || slotcount == 0) {
452 		cryptoerror(LOG_STDERR, gettext(
453 		    "failed to find any cryptographic provider,"
454 		    "please check with your system administrator: %s"),
455 		    pkcs11_strerror(rv));
456 		exitcode = EXIT_FAILURE;
457 		goto cleanup;
458 	}
459 
460 	/* Found at least one slot, allocate memory for slot list */
461 	pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
462 	if (pSlotList == NULL_PTR) {
463 		int err = errno;
464 		cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
465 		    strerror(err));
466 		exitcode = EXIT_FAILURE;
467 		goto cleanup;
468 	}
469 
470 	/* Get the list of slots */
471 	if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) {
472 		cryptoerror(LOG_STDERR, gettext(
473 		    "failed to find any cryptographic provider,"
474 		    "please check with your system administrator: %s"),
475 		    pkcs11_strerror(rv));
476 		exitcode = EXIT_FAILURE;
477 		goto cleanup;
478 	}
479 
480 	/*
481 	 * Obtain list of algorithms if -l option was given
482 	 */
483 	if (lflag) {
484 
485 		for (slot = 0; slot < slotcount; slot++) {
486 
487 			/* Iterate through each mechanism */
488 			for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) {
489 				rv = C_GetMechanismInfo(pSlotList[slot],
490 				    mech_aliases[mek].type, &info);
491 
492 				/* Only check algorithms that can be used */
493 				if ((rv != CKR_OK) ||
494 				    (!mac_cmd && (info.flags & CKF_SIGN)) ||
495 				    (mac_cmd && (info.flags & CKF_DIGEST)))
496 					continue;
497 
498 				/*
499 				 * Set to minimum/maximum key sizes assuming
500 				 * the values available are not 0.
501 				 */
502 				if (info.ulMinKeySize && (info.ulMinKeySize <
503 				    mech_aliases[mek].keysize_min))
504 					mech_aliases[mek].keysize_min =
505 					    info.ulMinKeySize;
506 
507 				if (info.ulMaxKeySize && (info.ulMaxKeySize >
508 				    mech_aliases[mek].keysize_max))
509 					mech_aliases[mek].keysize_max =
510 					    info.ulMaxKeySize;
511 
512 				mech_aliases[mek].available = B_TRUE;
513 			}
514 
515 		}
516 
517 		algorithm_list(mac_cmd);
518 
519 		goto cleanup;
520 	}
521 
522 	/*
523 	 * Find a slot with matching mechanism
524 	 *
525 	 * If -K is specified, we find the slot id for the token first, then
526 	 * check if the slot supports the algorithm.
527 	 */
528 	i = 0;
529 	if (Kflag) {
530 		kmfrv = kmf_pk11_token_lookup(NULL, token_label,
531 		    &token_slot_id);
532 		if (kmfrv != KMF_OK) {
533 			cryptoerror(LOG_STDERR,
534 			    gettext("no matching PKCS#11 token"));
535 			exitcode = EXIT_FAILURE;
536 			goto cleanup;
537 		}
538 		rv = C_GetMechanismInfo(token_slot_id, mech_type, &info);
539 		if (rv == CKR_OK && (info.flags & CKF_SIGN))
540 			slotID = token_slot_id;
541 		else
542 			i = slotcount;
543 
544 	} else {
545 		for (i = 0; i < slotcount; i++) {
546 			slotID = pSlotList[i];
547 			rv = C_GetMechanismInfo(slotID, mech_type, &info);
548 			if (rv != CKR_OK) {
549 				continue; /* to the next slot */
550 			} else {
551 				if (mac_cmd) {
552 					/*
553 					 * Make sure the slot supports
554 					 * PKCS5 key generation if we
555 					 * will be using it later.
556 					 * We use it whenever the key
557 					 * is entered at command line.
558 					 */
559 					if ((info.flags & CKF_SIGN) &&
560 					    (keyfile == NULL)) {
561 						CK_MECHANISM_INFO kg_info;
562 						rv = C_GetMechanismInfo(slotID,
563 						    CKM_PKCS5_PBKD2, &kg_info);
564 						if (rv == CKR_OK)
565 							break;
566 					} else if (info.flags & CKF_SIGN) {
567 						break;
568 					}
569 				} else {
570 					if (info.flags & CKF_DIGEST)
571 						break;
572 				}
573 			}
574 		}
575 	}
576 
577 	/* Show error if no matching mechanism found */
578 	if (i == slotcount) {
579 		cryptoerror(LOG_STDERR,
580 		    gettext("no cryptographic provider was "
581 		    "found for this algorithm -- %s"), algo_str);
582 		exitcode = EXIT_FAILURE;
583 		goto cleanup;
584 	}
585 
586 	/* Mechanism is supported. Go ahead & open a session */
587 	rv = C_OpenSession(slotID, CKF_SERIAL_SESSION,
588 	    NULL_PTR, NULL, &hSession);
589 
590 	if (rv != CKR_OK) {
591 		cryptoerror(LOG_STDERR,
592 		    gettext("can not open PKCS#11 session: %s"),
593 		    pkcs11_strerror(rv));
594 		exitcode = EXIT_FAILURE;
595 		goto cleanup;
596 	}
597 
598 	/* Create a key object for mac operation */
599 	if (mac_cmd) {
600 		/*
601 		 * If we read keybytes from a file,
602 		 * do NOT process them with C_GenerateKey,
603 		 * treat them as raw keydata bytes and
604 		 * create a key object for them.
605 		 */
606 		if (keyfile) {
607 			/* XXX : why wasn't SUNW_C_KeyToObject used here? */
608 			CK_OBJECT_CLASS class = CKO_SECRET_KEY;
609 			CK_KEY_TYPE tmpl_keytype = CKK_GENERIC_SECRET;
610 			CK_BBOOL false = FALSE;
611 			int nattr = 0;
612 			CK_ATTRIBUTE template[5];
613 
614 			if (mech_type == CKM_DES_MAC) {
615 				tmpl_keytype = CKK_DES;
616 			}
617 			template[nattr].type = CKA_CLASS;
618 			template[nattr].pValue = &class;
619 			template[nattr].ulValueLen = sizeof (class);
620 			nattr++;
621 
622 			template[nattr].type = CKA_KEY_TYPE;
623 			template[nattr].pValue = &tmpl_keytype;
624 			template[nattr].ulValueLen = sizeof (tmpl_keytype);
625 			nattr++;
626 
627 			template[nattr].type = CKA_SIGN;
628 			template[nattr].pValue = &true;
629 			template[nattr].ulValueLen = sizeof (true);
630 			nattr++;
631 
632 			template[nattr].type = CKA_TOKEN;
633 			template[nattr].pValue = &false;
634 			template[nattr].ulValueLen = sizeof (false);
635 			nattr++;
636 
637 			template[nattr].type = CKA_VALUE;
638 			template[nattr].pValue = pkeydata;
639 			template[nattr].ulValueLen = keylen;
640 			nattr++;
641 
642 			rv = C_CreateObject(hSession, template, nattr, &key);
643 
644 		} else if (Kflag) {
645 
646 			if (mech_type == CKM_DES_MAC) {
647 				keytype = CKK_DES;
648 			} else {
649 				keytype = CKK_GENERIC_SECRET;
650 			}
651 
652 			rv = get_token_key(hSession, keytype, key_label,
653 			    pkeydata, keylen, &key);
654 			if (rv != CKR_OK) {
655 				exitcode = EXIT_FAILURE;
656 				goto cleanup;
657 			}
658 		} else {
659 			CK_KEY_TYPE keytype;
660 			if (mech_type == CKM_DES_MAC) {
661 				keytype = CKK_DES;
662 				keysize = 0;
663 			} else {
664 				keytype = CKK_GENERIC_SECRET;
665 				keysize = 16; /* 128 bits */
666 			}
667 			/*
668 			 * We use a fixed salt (0x0a, 0x0a, 0x0a ...)
669 			 * for creating the key so that the end user
670 			 * will be able to generate the same 'mac'
671 			 * using the same passphrase.
672 			 */
673 			(void) memset(salt, 0x0a, sizeof (salt));
674 			rv = pkcs11_PasswdToPBKD2Object(hSession,
675 			    (char *)pkeydata, (size_t)keylen, (void *)salt,
676 			    sizeof (salt), iterations, keytype, keysize,
677 			    CKF_SIGN, &key);
678 		}
679 
680 		if (rv != CKR_OK) {
681 			cryptoerror(LOG_STDERR,
682 			    gettext("unable to create key for crypto "
683 			    "operation: %s"), pkcs11_strerror(rv));
684 			exitcode = EXIT_FAILURE;
685 			goto cleanup;
686 		}
687 	}
688 
689 	/* Allocate a buffer to store result. */
690 	resultlen = RESULTLEN;
691 	if ((resultbuf = malloc(resultlen)) == NULL) {
692 		int err = errno;
693 		cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
694 		    strerror(err));
695 		exitcode = EXIT_FAILURE;
696 		goto cleanup;
697 	}
698 
699 	/* Allocate a buffer to store result string */
700 	resultstrlen = RESULTLEN;
701 	if ((resultstr = malloc(resultstrlen)) == NULL) {
702 		int err = errno;
703 		cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
704 		    strerror(err));
705 		exitcode = EXIT_FAILURE;
706 		goto cleanup;
707 	}
708 
709 	mech.mechanism = mech_type;
710 	mech.pParameter = NULL_PTR;
711 	mech.ulParameterLen = 0;
712 	exitcode = EXIT_SUCCESS;
713 	i = 0;
714 
715 	do {
716 		if (filecount > 0 && filelist != NULL) {
717 			filename = filelist[i];
718 			if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) ==
719 			    -1) {
720 				cryptoerror(LOG_STDERR, gettext(
721 				    "can not open input file %s\n"), filename);
722 				exitcode = EXIT_USAGE;
723 				continue;
724 			}
725 		} else {
726 			fd = 0; /* use stdin */
727 		}
728 
729 		/*
730 		 * Perform the operation
731 		 */
732 		if (mac_cmd) {
733 			rv = do_mac(hSession, &mech, fd, key, &resultbuf,
734 			    &resultlen);
735 		} else {
736 			rv = do_digest(hSession, &mech, fd, &resultbuf,
737 			    &resultlen);
738 		}
739 
740 		if (rv != CKR_OK) {
741 			cryptoerror(LOG_STDERR,
742 			    gettext("crypto operation failed for "
743 			    "file %s: %s\n"),
744 			    filename ? filename : "STDIN",
745 			    pkcs11_strerror(rv));
746 			exitcode = EXIT_FAILURE;
747 			continue;
748 		}
749 
750 		/* if result size has changed, allocate a bigger resulstr buf */
751 		if (resultlen != RESULTLEN) {
752 			resultstrlen = 2 * resultlen + 1;
753 			resultstr = realloc(resultstr, resultstrlen);
754 
755 			if (resultstr == NULL) {
756 				int err = errno;
757 				cryptoerror(LOG_STDERR,
758 				    gettext("realloc: %s\n"), strerror(err));
759 				exitcode =  EXIT_FAILURE;
760 				goto cleanup;
761 			}
762 		}
763 
764 		/* Output the result */
765 		tohexstr(resultbuf, resultlen, resultstr, resultstrlen);
766 
767 		/* Include mechanism name for verbose */
768 		if (vflag)
769 			(void) fprintf(stdout, "%s ", algo_str);
770 
771 		/* Include file name for multiple files, or if verbose */
772 		if (filecount > 1 || (vflag && filecount > 0)) {
773 			(void) fprintf(stdout, "(%s) = ", filename);
774 		}
775 
776 		(void) fprintf(stdout, "%s\n", resultstr);
777 		(void) close(fd);
778 
779 
780 	} while (++i < filecount);
781 
782 
783 	/* clear and free the key */
784 	if (mac_cmd) {
785 		(void) memset(pkeydata, 0, keylen);
786 		free(pkeydata);
787 		pkeydata = NULL;
788 	}
789 
790 cleanup:
791 	if (resultbuf != NULL) {
792 		free(resultbuf);
793 	}
794 
795 	if (resultstr != NULL) {
796 		free(resultstr);
797 	}
798 
799 	if (pSlotList != NULL) {
800 		free(pSlotList);
801 	}
802 
803 	if (!Kflag && key != (CK_OBJECT_HANDLE) 0) {
804 		(void) C_DestroyObject(hSession, key);
805 	}
806 
807 	if (hSession != CK_INVALID_HANDLE)
808 		(void) C_CloseSession(hSession);
809 
810 	(void) C_Finalize(NULL_PTR);
811 
812 	return (exitcode);
813 }
814 
815 /*
816  * do_digest - Compute digest of a file
817  *
818  *  hSession - session
819  *  pmech - ptr to mechanism to be used for digest
820  *  fd  - file descriptor
821  *  pdigest - buffer  where digest result is returned
822  *  pdigestlen - length of digest buffer on input,
823  *               length of result on output
824  */
825 static CK_RV
826 do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
827 	int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen)
828 {
829 	CK_RV rv;
830 	ssize_t nread;
831 	int saved_errno;
832 
833 	if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) {
834 		return (rv);
835 	}
836 
837 	while ((nread = read(fd, buf, sizeof (buf))) > 0) {
838 		/* Get the digest */
839 		rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread);
840 		if (rv != CKR_OK)
841 			return (rv);
842 	}
843 
844 	saved_errno = errno; /* for later use */
845 
846 	/*
847 	 * Perform the C_DigestFinal, even if there is a read error.
848 	 * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE
849 	 * next time it is called (for another file)
850 	 */
851 
852 	rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
853 
854 	/* result too big to fit? Allocate a bigger buffer */
855 	if (rv == CKR_BUFFER_TOO_SMALL) {
856 		*pdigest = realloc(*pdigest, *pdigestlen);
857 
858 		if (*pdigest == NULL_PTR) {
859 			int err = errno;
860 			cryptoerror(LOG_STDERR,
861 			    gettext("realloc: %s\n"), strerror(err));
862 			return (CKR_HOST_MEMORY);
863 		}
864 
865 		rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
866 	}
867 
868 
869 	/* There was a read error */
870 	if (nread == -1) {
871 		cryptoerror(LOG_STDERR, gettext(
872 		    "error reading file: %s"), strerror(saved_errno));
873 		return (CKR_GENERAL_ERROR);
874 	} else {
875 		return (rv);
876 	}
877 }
878 
879 /*
880  * do_mac - Compute mac of a file
881  *
882  *  hSession - session
883  *  pmech - ptr to mechanism to be used
884  *  fd  - file descriptor
885  *  key - key to be used
886  *  psignature - ptr buffer  where mac result is returned
887  *		returns new buf if current buf is small
888  *  psignaturelen - length of mac buffer on input,
889  *               length of result on output
890  */
891 static CK_RV
892 do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
893 	int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature,
894 	CK_ULONG_PTR psignaturelen)
895 {
896 	CK_RV rv;
897 	ssize_t nread;
898 	int saved_errno;
899 
900 	if ((rv = C_SignInit(hSession, pmech, key)) != CKR_OK) {
901 		return (rv);
902 	}
903 
904 	while ((nread = read(fd, buf, sizeof (buf))) > 0) {
905 		/* Get the MAC */
906 		rv = C_SignUpdate(hSession, buf, (CK_ULONG)nread);
907 		if (rv != CKR_OK)
908 			return (rv);
909 	}
910 
911 	saved_errno = errno; /* for later use */
912 
913 	/*
914 	 * Perform the C_SignFinal, even if there is a read error.
915 	 * Otherwise C_SignInit will return CKR_OPERATION_ACTIVE
916 	 * next time it is called (for another file)
917 	 */
918 
919 	rv = C_SignFinal(hSession, *psignature, psignaturelen);
920 
921 	/* result too big to fit? Allocate a bigger buffer */
922 	if (rv == CKR_BUFFER_TOO_SMALL) {
923 		*psignature = realloc(*psignature, *psignaturelen);
924 
925 		if (*psignature == NULL_PTR) {
926 			int err = errno;
927 			cryptoerror(LOG_STDERR,
928 			    gettext("realloc: %s\n"), strerror(err));
929 			return (CKR_HOST_MEMORY);
930 		}
931 
932 		rv = C_SignFinal(hSession, *psignature, psignaturelen);
933 	}
934 
935 	/* There was a read error */
936 	if (nread == -1) {
937 		cryptoerror(LOG_STDERR, gettext("error reading file: %s"),
938 		    strerror(saved_errno));
939 		return (CKR_GENERAL_ERROR);
940 	} else {
941 		return (rv);
942 	}
943 }
944