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