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