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