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