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
main(int argc,char ** argv)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
usage(boolean_t mac_cmd)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
algorithm_list(boolean_t mac_cmd)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
get_token_key(CK_SESSION_HANDLE hSession,CK_KEY_TYPE keytype,char * keylabel,CK_BYTE * password,int password_len,CK_OBJECT_HANDLE * keyobj)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
execute_cmd(char * algo_str,int filecount,char ** filelist,boolean_t mac_cmd)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
do_digest(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pmech,int fd,CK_BYTE_PTR * pdigest,CK_ULONG_PTR pdigestlen)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
do_mac(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pmech,int fd,CK_OBJECT_HANDLE key,CK_BYTE_PTR * psignature,CK_ULONG_PTR psignaturelen)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