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