1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * digest.c 28 * 29 * Implements digest(1) and mac(1) commands 30 * If command name is mac, performs mac operation 31 * else perform digest operation 32 * 33 * See the man pages for digest and mac for details on 34 * how these commands work. 35 */ 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <fcntl.h> 41 #include <ctype.h> 42 #include <strings.h> 43 #include <libintl.h> 44 #include <libgen.h> 45 #include <locale.h> 46 #include <errno.h> 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <security/cryptoki.h> 50 #include <limits.h> 51 #include <cryptoutil.h> 52 #include <kmfapi.h> 53 54 #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 digest command */ 75 #define DIGEST_OPTIONS "lva:" /* for getopt */ 76 77 /* Saved command line options */ 78 static boolean_t vflag = B_FALSE; /* -v (verbose) flag, optional */ 79 static boolean_t aflag = B_FALSE; /* -a <algorithm> flag, required */ 80 static boolean_t lflag = B_FALSE; /* -l flag, for mac and digest */ 81 static boolean_t kflag = B_FALSE; /* -k keyfile */ 82 static boolean_t Tflag = B_FALSE; /* -T token_spec */ 83 static boolean_t Kflag = B_FALSE; /* -K key_label */ 84 85 static char *keyfile = NULL; /* name of file containing key value */ 86 static char *token_label = NULL; /* tokensSpec: tokenName[:manufId[:serial]] */ 87 static char *key_label = NULL; /* PKCS#11 symmetric token key label */ 88 89 static CK_BYTE buf[BUFFERSIZE]; 90 91 struct mech_alias { 92 CK_MECHANISM_TYPE type; 93 char *alias; 94 CK_ULONG keysize_min; 95 CK_ULONG keysize_max; 96 int keysize_unit; 97 boolean_t available; 98 }; 99 100 #define MECH_ALIASES_COUNT 11 101 102 static struct mech_alias mech_aliases[] = { 103 { CKM_SHA_1, "sha1", ULONG_MAX, 0L, 8, B_FALSE }, 104 { CKM_MD5, "md5", ULONG_MAX, 0L, 8, B_FALSE }, 105 { CKM_DES_MAC, "des_mac", ULONG_MAX, 0L, 8, B_FALSE }, 106 { CKM_SHA_1_HMAC, "sha1_hmac", ULONG_MAX, 0L, 8, B_FALSE }, 107 { CKM_MD5_HMAC, "md5_hmac", ULONG_MAX, 0L, 8, B_FALSE }, 108 { CKM_SHA256, "sha256", ULONG_MAX, 0L, 8, B_FALSE }, 109 { CKM_SHA384, "sha384", ULONG_MAX, 0L, 8, B_FALSE }, 110 { CKM_SHA512, "sha512", ULONG_MAX, 0L, 8, B_FALSE }, 111 { CKM_SHA256_HMAC, "sha256_hmac", ULONG_MAX, 0L, 8, B_FALSE }, 112 { CKM_SHA384_HMAC, "sha384_hmac", ULONG_MAX, 0L, 8, B_FALSE }, 113 { CKM_SHA512_HMAC, "sha512_hmac", ULONG_MAX, 0L, 8, B_FALSE } 114 }; 115 116 static CK_BBOOL true = TRUE; 117 118 static void usage(boolean_t mac_cmd); 119 static int execute_cmd(char *algo_str, int filecount, 120 char **filelist, boolean_t mac_cmd); 121 static CK_RV do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, 122 int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature, 123 CK_ULONG_PTR psignaturelen); 124 static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, 125 int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen); 126 127 int 128 main(int argc, char **argv) 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 || (keyfile == NULL)) ? 434 gettext("invalid passphrase.") : 435 gettext("invalid key.")); 436 return (EXIT_FAILURE); 437 } 438 } 439 } 440 441 /* Initialize, and get list of slots */ 442 rv = C_Initialize(NULL); 443 if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 444 cryptoerror(LOG_STDERR, 445 gettext("failed to initialize PKCS #11 framework: %s"), 446 pkcs11_strerror(rv)); 447 return (EXIT_FAILURE); 448 } 449 450 /* Get slot count */ 451 rv = C_GetSlotList(0, NULL_PTR, &slotcount); 452 if (rv != CKR_OK || slotcount == 0) { 453 cryptoerror(LOG_STDERR, gettext( 454 "failed to find any cryptographic provider; " 455 "please check with your system administrator: %s"), 456 pkcs11_strerror(rv)); 457 exitcode = EXIT_FAILURE; 458 goto cleanup; 459 } 460 461 /* Found at least one slot, allocate memory for slot list */ 462 pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); 463 if (pSlotList == NULL_PTR) { 464 int err = errno; 465 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 466 strerror(err)); 467 exitcode = EXIT_FAILURE; 468 goto cleanup; 469 } 470 471 /* Get the list of slots */ 472 if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { 473 cryptoerror(LOG_STDERR, gettext( 474 "failed to find any cryptographic provider; " 475 "please check with your system administrator: %s"), 476 pkcs11_strerror(rv)); 477 exitcode = EXIT_FAILURE; 478 goto cleanup; 479 } 480 481 /* 482 * Obtain list of algorithms if -l option was given 483 */ 484 if (lflag) { 485 486 for (slot = 0; slot < slotcount; slot++) { 487 488 /* Iterate through each mechanism */ 489 for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { 490 rv = C_GetMechanismInfo(pSlotList[slot], 491 mech_aliases[mek].type, &info); 492 493 /* Only check algorithms that can be used */ 494 if ((rv != CKR_OK) || 495 (!mac_cmd && (info.flags & CKF_SIGN)) || 496 (mac_cmd && (info.flags & CKF_DIGEST))) 497 continue; 498 499 /* 500 * Set to minimum/maximum key sizes assuming 501 * the values available are not 0. 502 */ 503 if (info.ulMinKeySize && (info.ulMinKeySize < 504 mech_aliases[mek].keysize_min)) 505 mech_aliases[mek].keysize_min = 506 info.ulMinKeySize; 507 508 if (info.ulMaxKeySize && (info.ulMaxKeySize > 509 mech_aliases[mek].keysize_max)) 510 mech_aliases[mek].keysize_max = 511 info.ulMaxKeySize; 512 513 mech_aliases[mek].available = B_TRUE; 514 } 515 516 } 517 518 algorithm_list(mac_cmd); 519 520 goto cleanup; 521 } 522 523 /* 524 * Find a slot with matching mechanism 525 * 526 * If -K is specified, we find the slot id for the token first, then 527 * check if the slot supports the algorithm. 528 */ 529 i = 0; 530 if (Kflag) { 531 kmfrv = kmf_pk11_token_lookup(NULL, token_label, 532 &token_slot_id); 533 if (kmfrv != KMF_OK) { 534 cryptoerror(LOG_STDERR, 535 gettext("no matching PKCS#11 token")); 536 exitcode = EXIT_FAILURE; 537 goto cleanup; 538 } 539 rv = C_GetMechanismInfo(token_slot_id, mech_type, &info); 540 if (rv == CKR_OK && (info.flags & CKF_SIGN)) 541 slotID = token_slot_id; 542 else 543 i = slotcount; 544 545 } else { 546 for (i = 0; i < slotcount; i++) { 547 slotID = pSlotList[i]; 548 rv = C_GetMechanismInfo(slotID, mech_type, &info); 549 if (rv != CKR_OK) { 550 continue; /* to the next slot */ 551 } else { 552 if (mac_cmd) { 553 /* 554 * Make sure the slot supports 555 * PKCS5 key generation if we 556 * will be using it later. 557 * We use it whenever the key 558 * is entered at command line. 559 */ 560 if ((info.flags & CKF_SIGN) && 561 (keyfile == NULL)) { 562 CK_MECHANISM_INFO kg_info; 563 rv = C_GetMechanismInfo(slotID, 564 CKM_PKCS5_PBKD2, &kg_info); 565 if (rv == CKR_OK) 566 break; 567 } else if (info.flags & CKF_SIGN) { 568 break; 569 } 570 } else { 571 if (info.flags & CKF_DIGEST) 572 break; 573 } 574 } 575 } 576 } 577 578 /* Show error if no matching mechanism found */ 579 if (i == slotcount) { 580 cryptoerror(LOG_STDERR, 581 gettext("no cryptographic provider was " 582 "found for this algorithm -- %s"), algo_str); 583 exitcode = EXIT_FAILURE; 584 goto cleanup; 585 } 586 587 /* Mechanism is supported. Go ahead & open a session */ 588 rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, 589 NULL_PTR, NULL, &hSession); 590 591 if (rv != CKR_OK) { 592 cryptoerror(LOG_STDERR, 593 gettext("can not open PKCS#11 session: %s"), 594 pkcs11_strerror(rv)); 595 exitcode = EXIT_FAILURE; 596 goto cleanup; 597 } 598 599 /* Create a key object for mac operation */ 600 if (mac_cmd) { 601 /* 602 * If we read keybytes from a file, 603 * do NOT process them with C_GenerateKey, 604 * treat them as raw keydata bytes and 605 * create a key object for them. 606 */ 607 if (keyfile) { 608 /* XXX : why wasn't SUNW_C_KeyToObject used here? */ 609 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 610 CK_KEY_TYPE tmpl_keytype = CKK_GENERIC_SECRET; 611 CK_BBOOL false = FALSE; 612 int nattr = 0; 613 CK_ATTRIBUTE template[5]; 614 615 if (mech_type == CKM_DES_MAC) { 616 tmpl_keytype = CKK_DES; 617 } 618 template[nattr].type = CKA_CLASS; 619 template[nattr].pValue = &class; 620 template[nattr].ulValueLen = sizeof (class); 621 nattr++; 622 623 template[nattr].type = CKA_KEY_TYPE; 624 template[nattr].pValue = &tmpl_keytype; 625 template[nattr].ulValueLen = sizeof (tmpl_keytype); 626 nattr++; 627 628 template[nattr].type = CKA_SIGN; 629 template[nattr].pValue = &true; 630 template[nattr].ulValueLen = sizeof (true); 631 nattr++; 632 633 template[nattr].type = CKA_TOKEN; 634 template[nattr].pValue = &false; 635 template[nattr].ulValueLen = sizeof (false); 636 nattr++; 637 638 template[nattr].type = CKA_VALUE; 639 template[nattr].pValue = pkeydata; 640 template[nattr].ulValueLen = keylen; 641 nattr++; 642 643 rv = C_CreateObject(hSession, template, nattr, &key); 644 645 } else if (Kflag) { 646 647 if (mech_type == CKM_DES_MAC) { 648 keytype = CKK_DES; 649 } else { 650 keytype = CKK_GENERIC_SECRET; 651 } 652 653 rv = get_token_key(hSession, keytype, key_label, 654 pkeydata, keylen, &key); 655 if (rv != CKR_OK) { 656 exitcode = EXIT_FAILURE; 657 goto cleanup; 658 } 659 } else { 660 CK_KEY_TYPE keytype; 661 if (mech_type == CKM_DES_MAC) { 662 keytype = CKK_DES; 663 keysize = 0; 664 } else { 665 keytype = CKK_GENERIC_SECRET; 666 keysize = 16; /* 128 bits */ 667 } 668 /* 669 * We use a fixed salt (0x0a, 0x0a, 0x0a ...) 670 * for creating the key so that the end user 671 * will be able to generate the same 'mac' 672 * using the same passphrase. 673 */ 674 (void) memset(salt, 0x0a, sizeof (salt)); 675 rv = pkcs11_PasswdToPBKD2Object(hSession, 676 (char *)pkeydata, (size_t)keylen, (void *)salt, 677 sizeof (salt), iterations, keytype, keysize, 678 CKF_SIGN, &key); 679 } 680 681 if (rv != CKR_OK) { 682 cryptoerror(LOG_STDERR, 683 gettext("unable to create key for crypto " 684 "operation: %s"), pkcs11_strerror(rv)); 685 exitcode = EXIT_FAILURE; 686 goto cleanup; 687 } 688 } 689 690 /* Allocate a buffer to store result. */ 691 resultlen = RESULTLEN; 692 if ((resultbuf = malloc(resultlen)) == NULL) { 693 int err = errno; 694 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 695 strerror(err)); 696 exitcode = EXIT_FAILURE; 697 goto cleanup; 698 } 699 700 /* Allocate a buffer to store result string */ 701 resultstrlen = RESULTLEN; 702 if ((resultstr = malloc(resultstrlen)) == NULL) { 703 int err = errno; 704 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 705 strerror(err)); 706 exitcode = EXIT_FAILURE; 707 goto cleanup; 708 } 709 710 mech.mechanism = mech_type; 711 mech.pParameter = NULL_PTR; 712 mech.ulParameterLen = 0; 713 exitcode = EXIT_SUCCESS; 714 i = 0; 715 716 do { 717 if (filecount > 0 && filelist != NULL) { 718 filename = filelist[i]; 719 if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == 720 -1) { 721 cryptoerror(LOG_STDERR, gettext( 722 "can not open input file %s\n"), filename); 723 exitcode = EXIT_USAGE; 724 continue; 725 } 726 } else { 727 fd = 0; /* use stdin */ 728 } 729 730 /* 731 * Perform the operation 732 */ 733 if (mac_cmd) { 734 rv = do_mac(hSession, &mech, fd, key, &resultbuf, 735 &resultlen); 736 } else { 737 rv = do_digest(hSession, &mech, fd, &resultbuf, 738 &resultlen); 739 } 740 741 if (rv != CKR_OK) { 742 cryptoerror(LOG_STDERR, 743 gettext("crypto operation failed for " 744 "file %s: %s\n"), 745 filename ? filename : "STDIN", 746 pkcs11_strerror(rv)); 747 exitcode = EXIT_FAILURE; 748 continue; 749 } 750 751 /* if result size has changed, allocate a bigger resulstr buf */ 752 if (resultlen != RESULTLEN) { 753 resultstrlen = 2 * resultlen + 1; 754 resultstr = realloc(resultstr, resultstrlen); 755 756 if (resultstr == NULL) { 757 int err = errno; 758 cryptoerror(LOG_STDERR, 759 gettext("realloc: %s\n"), strerror(err)); 760 exitcode = EXIT_FAILURE; 761 goto cleanup; 762 } 763 } 764 765 /* Output the result */ 766 tohexstr(resultbuf, resultlen, resultstr, resultstrlen); 767 768 /* Include mechanism name for verbose */ 769 if (vflag) 770 (void) fprintf(stdout, "%s ", algo_str); 771 772 /* Include file name for multiple files, or if verbose */ 773 if (filecount > 1 || (vflag && filecount > 0)) { 774 (void) fprintf(stdout, "(%s) = ", filename); 775 } 776 777 (void) fprintf(stdout, "%s\n", resultstr); 778 (void) close(fd); 779 780 781 } while (++i < filecount); 782 783 784 /* clear and free the key */ 785 if (mac_cmd) { 786 (void) memset(pkeydata, 0, keylen); 787 free(pkeydata); 788 pkeydata = NULL; 789 } 790 791 cleanup: 792 if (resultbuf != NULL) { 793 free(resultbuf); 794 } 795 796 if (resultstr != NULL) { 797 free(resultstr); 798 } 799 800 if (pSlotList != NULL) { 801 free(pSlotList); 802 } 803 804 if (!Kflag && key != (CK_OBJECT_HANDLE) 0) { 805 (void) C_DestroyObject(hSession, key); 806 } 807 808 if (hSession != CK_INVALID_HANDLE) 809 (void) C_CloseSession(hSession); 810 811 (void) C_Finalize(NULL_PTR); 812 813 return (exitcode); 814 } 815 816 /* 817 * do_digest - Compute digest of a file 818 * 819 * hSession - session 820 * pmech - ptr to mechanism to be used for digest 821 * fd - file descriptor 822 * pdigest - buffer where digest result is returned 823 * pdigestlen - length of digest buffer on input, 824 * length of result on output 825 */ 826 static CK_RV 827 do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, 828 int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen) 829 { 830 CK_RV rv; 831 ssize_t nread; 832 int saved_errno; 833 834 if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) { 835 return (rv); 836 } 837 838 while ((nread = read(fd, buf, sizeof (buf))) > 0) { 839 /* Get the digest */ 840 rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread); 841 if (rv != CKR_OK) 842 return (rv); 843 } 844 845 saved_errno = errno; /* for later use */ 846 847 /* 848 * Perform the C_DigestFinal, even if there is a read error. 849 * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE 850 * next time it is called (for another file) 851 */ 852 853 rv = C_DigestFinal(hSession, *pdigest, pdigestlen); 854 855 /* result too big to fit? Allocate a bigger buffer */ 856 if (rv == CKR_BUFFER_TOO_SMALL) { 857 *pdigest = realloc(*pdigest, *pdigestlen); 858 859 if (*pdigest == NULL_PTR) { 860 int err = errno; 861 cryptoerror(LOG_STDERR, 862 gettext("realloc: %s\n"), strerror(err)); 863 return (CKR_HOST_MEMORY); 864 } 865 866 rv = C_DigestFinal(hSession, *pdigest, pdigestlen); 867 } 868 869 870 /* There was a read error */ 871 if (nread == -1) { 872 cryptoerror(LOG_STDERR, gettext( 873 "error reading file: %s"), strerror(saved_errno)); 874 return (CKR_GENERAL_ERROR); 875 } else { 876 return (rv); 877 } 878 } 879 880 /* 881 * do_mac - Compute mac of a file 882 * 883 * hSession - session 884 * pmech - ptr to mechanism to be used 885 * fd - file descriptor 886 * key - key to be used 887 * psignature - ptr buffer where mac result is returned 888 * returns new buf if current buf is small 889 * psignaturelen - length of mac buffer on input, 890 * length of result on output 891 */ 892 static CK_RV 893 do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, 894 int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature, 895 CK_ULONG_PTR psignaturelen) 896 { 897 CK_RV rv; 898 ssize_t nread; 899 int saved_errno; 900 901 if ((rv = C_SignInit(hSession, pmech, key)) != CKR_OK) { 902 return (rv); 903 } 904 905 while ((nread = read(fd, buf, sizeof (buf))) > 0) { 906 /* Get the MAC */ 907 rv = C_SignUpdate(hSession, buf, (CK_ULONG)nread); 908 if (rv != CKR_OK) 909 return (rv); 910 } 911 912 saved_errno = errno; /* for later use */ 913 914 /* 915 * Perform the C_SignFinal, even if there is a read error. 916 * Otherwise C_SignInit will return CKR_OPERATION_ACTIVE 917 * next time it is called (for another file) 918 */ 919 920 rv = C_SignFinal(hSession, *psignature, psignaturelen); 921 922 /* result too big to fit? Allocate a bigger buffer */ 923 if (rv == CKR_BUFFER_TOO_SMALL) { 924 *psignature = realloc(*psignature, *psignaturelen); 925 926 if (*psignature == NULL_PTR) { 927 int err = errno; 928 cryptoerror(LOG_STDERR, 929 gettext("realloc: %s\n"), strerror(err)); 930 return (CKR_HOST_MEMORY); 931 } 932 933 rv = C_SignFinal(hSession, *psignature, psignaturelen); 934 } 935 936 /* There was a read error */ 937 if (nread == -1) { 938 cryptoerror(LOG_STDERR, gettext("error reading file: %s"), 939 strerror(saved_errno)); 940 return (CKR_GENERAL_ERROR); 941 } else { 942 return (rv); 943 } 944 } 945