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