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