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, attrs, hKey); 341 342 return (rv); 343 } 344 345 346 static int 347 get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype, 348 char *keylabel, CK_BYTE *password, int password_len, 349 CK_OBJECT_HANDLE *keyobj) 350 { 351 CK_RV rv; 352 CK_ATTRIBUTE pTmpl[10]; 353 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 354 CK_BBOOL true = 1; 355 CK_BBOOL is_token = 1; 356 CK_ULONG key_obj_count = 1; 357 int i; 358 CK_KEY_TYPE ckKeyType = keytype; 359 360 361 rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, 362 password_len); 363 if (rv != CKR_OK) { 364 (void) fprintf(stderr, "Cannot login to the token." 365 " error = %s\n", pkcs11_strerror(rv)); 366 return (-1); 367 } 368 369 i = 0; 370 pTmpl[i].type = CKA_TOKEN; 371 pTmpl[i].pValue = &is_token; 372 pTmpl[i].ulValueLen = sizeof (CK_BBOOL); 373 i++; 374 375 pTmpl[i].type = CKA_CLASS; 376 pTmpl[i].pValue = &class; 377 pTmpl[i].ulValueLen = sizeof (class); 378 i++; 379 380 pTmpl[i].type = CKA_LABEL; 381 pTmpl[i].pValue = keylabel; 382 pTmpl[i].ulValueLen = strlen(keylabel); 383 i++; 384 385 pTmpl[i].type = CKA_KEY_TYPE; 386 pTmpl[i].pValue = &ckKeyType; 387 pTmpl[i].ulValueLen = sizeof (ckKeyType); 388 i++; 389 390 pTmpl[i].type = CKA_PRIVATE; 391 pTmpl[i].pValue = &true; 392 pTmpl[i].ulValueLen = sizeof (true); 393 i++; 394 395 rv = C_FindObjectsInit(hSession, pTmpl, i); 396 if (rv != CKR_OK) { 397 goto out; 398 } 399 400 rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count); 401 (void) C_FindObjectsFinal(hSession); 402 403 out: 404 if (rv != CKR_OK) { 405 (void) fprintf(stderr, 406 "Cannot retrieve key object. error = %s\n", 407 pkcs11_strerror(rv)); 408 return (-1); 409 } 410 411 if (key_obj_count == 0) { 412 (void) fprintf(stderr, "Cannot find the key object.\n"); 413 return (-1); 414 } 415 416 return (0); 417 } 418 419 420 /* 421 * Execute the command. 422 * algo_str - name of algorithm 423 * filecount - no. of files to process, if 0, use stdin 424 * filelist - list of files 425 * mac_cmd - if true do mac else do digest 426 */ 427 static int 428 execute_cmd(char *algo_str, int filecount, char **filelist, boolean_t mac_cmd) 429 { 430 int fd; 431 char *filename = NULL; 432 CK_RV rv; 433 CK_ULONG slotcount; 434 CK_SLOT_ID slotID; 435 CK_SLOT_ID_PTR pSlotList = NULL; 436 CK_MECHANISM_TYPE mech_type; 437 CK_MECHANISM_INFO info; 438 CK_MECHANISM mech; 439 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; 440 CK_BYTE_PTR resultbuf = NULL; 441 CK_ULONG resultlen; 442 CK_BYTE_PTR pkeydata = NULL; 443 CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; 444 int keylen = 0; /* key length */ 445 char *resultstr = NULL; /* result in hex string */ 446 int resultstrlen; /* result string length */ 447 int i; 448 int exitcode = EXIT_SUCCESS; /* return code */ 449 int slot, mek; /* index variables */ 450 int mech_match = 0; 451 CK_BYTE salt[PBKD2_SALT_SIZE]; 452 CK_ULONG keysize; 453 CK_ULONG iterations = PBKD2_ITERATIONS; 454 CK_KEY_TYPE keytype; 455 KMF_RETURN kmfrv; 456 CK_SLOT_ID token_slot_id; 457 458 if (aflag) { 459 /* 460 * Determine if algorithm/mechanism is valid 461 */ 462 for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; 463 mech_match++) { 464 if (strcmp(algo_str, 465 mech_aliases[mech_match].alias) == 0) { 466 mech_type = mech_aliases[mech_match].type; 467 break; 468 } 469 470 } 471 472 if (mech_match == MECH_ALIASES_COUNT) { 473 cryptoerror(LOG_STDERR, 474 gettext("unknown algorithm -- %s"), algo_str); 475 return (EXIT_FAILURE); 476 } 477 478 /* Get key to do a MAC operation */ 479 if (mac_cmd) { 480 if (Kflag) { 481 int status; 482 483 if (token_label == NULL || 484 !strlen(token_label)) { 485 token_label = PK_DEFAULT_PK11TOKEN; 486 } 487 488 status = getpasswd(token_label, &pkeydata, 489 (CK_ULONG *)&keylen); 490 if (status == -1) { 491 cryptoerror(LOG_STDERR, 492 gettext("invalid passphrase.")); 493 return (EXIT_FAILURE); 494 } 495 496 } else { 497 keylen = getkey(keyfile, &pkeydata); 498 if (keylen <= 0 || pkeydata == NULL) { 499 cryptoerror(LOG_STDERR, 500 gettext("invalid key.")); 501 return (EXIT_FAILURE); 502 } 503 } 504 } 505 } 506 507 /* Initialize, and get list of slots */ 508 rv = C_Initialize(NULL); 509 if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 510 cryptoerror(LOG_STDERR, 511 gettext("failed to initialize PKCS #11 framework: %s"), 512 pkcs11_strerror(rv)); 513 return (EXIT_FAILURE); 514 } 515 516 /* Get slot count */ 517 rv = C_GetSlotList(0, NULL_PTR, &slotcount); 518 if (rv != CKR_OK || slotcount == 0) { 519 cryptoerror(LOG_STDERR, gettext( 520 "failed to find any cryptographic provider," 521 "please check with your system administrator: %s"), 522 pkcs11_strerror(rv)); 523 exitcode = EXIT_FAILURE; 524 goto cleanup; 525 } 526 527 /* Found at least one slot, allocate memory for slot list */ 528 pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); 529 if (pSlotList == NULL_PTR) { 530 int err = errno; 531 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 532 strerror(err)); 533 exitcode = EXIT_FAILURE; 534 goto cleanup; 535 } 536 537 /* Get the list of slots */ 538 if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { 539 cryptoerror(LOG_STDERR, gettext( 540 "failed to find any cryptographic provider," 541 "please check with your system administrator: %s"), 542 pkcs11_strerror(rv)); 543 exitcode = EXIT_FAILURE; 544 goto cleanup; 545 } 546 547 /* 548 * Obtain list of algorithms if -l option was given 549 */ 550 if (lflag) { 551 552 for (slot = 0; slot < slotcount; slot++) { 553 554 /* Iterate through each mechanism */ 555 for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { 556 rv = C_GetMechanismInfo(pSlotList[slot], 557 mech_aliases[mek].type, &info); 558 559 /* Only check algorithms that can be used */ 560 if ((rv != CKR_OK) || 561 (!mac_cmd && (info.flags & CKF_SIGN)) || 562 (mac_cmd && (info.flags & CKF_DIGEST))) 563 continue; 564 565 /* 566 * Set to minimum/maximum key sizes assuming 567 * the values available are not 0. 568 */ 569 if (info.ulMinKeySize && (info.ulMinKeySize < 570 mech_aliases[mek].keysize_min)) 571 mech_aliases[mek].keysize_min = 572 info.ulMinKeySize; 573 574 if (info.ulMaxKeySize && (info.ulMaxKeySize > 575 mech_aliases[mek].keysize_max)) 576 mech_aliases[mek].keysize_max = 577 info.ulMaxKeySize; 578 579 mech_aliases[mek].available = B_TRUE; 580 } 581 582 } 583 584 algorithm_list(mac_cmd); 585 586 goto cleanup; 587 } 588 589 /* 590 * Find a slot with matching mechanism 591 * 592 * If -K is specified, we find the slot id for the token first, then 593 * check if the slot supports the algorithm. 594 */ 595 i = 0; 596 if (Kflag) { 597 kmfrv = kmf_pk11_token_lookup(NULL, token_label, 598 &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, nattr, &key); 709 710 } else if (Kflag) { 711 712 if (mech_type == CKM_DES_MAC) { 713 keytype = CKK_DES; 714 } else { 715 keytype = CKK_GENERIC_SECRET; 716 } 717 718 rv = get_token_key(hSession, keytype, key_label, 719 pkeydata, keylen, &key); 720 if (rv != CKR_OK) { 721 exitcode = EXIT_FAILURE; 722 goto cleanup; 723 } 724 } else { 725 CK_KEY_TYPE keytype; 726 if (mech_type == CKM_DES_MAC) { 727 keytype = CKK_DES; 728 keysize = 0; 729 } else { 730 keytype = CKK_GENERIC_SECRET; 731 keysize = 16; /* 128 bits */ 732 } 733 /* 734 * We use a fixed salt (0x0a, 0x0a, 0x0a ...) 735 * for creating the key so that the end user 736 * will be able to generate the same 'mac' 737 * using the same passphrase. 738 */ 739 (void) memset(salt, 0x0a, sizeof (salt)); 740 rv = generate_pkcs5_key(hSession, 741 salt, sizeof (salt), iterations, pkeydata, 742 keytype, keylen, keysize, &key); 743 } 744 745 if (rv != CKR_OK) { 746 cryptoerror(LOG_STDERR, 747 gettext("unable to create key for crypto " 748 "operation: %s"), pkcs11_strerror(rv)); 749 exitcode = EXIT_FAILURE; 750 goto cleanup; 751 } 752 } 753 754 /* Allocate a buffer to store result. */ 755 resultlen = RESULTLEN; 756 if ((resultbuf = malloc(resultlen)) == NULL) { 757 int err = errno; 758 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 759 strerror(err)); 760 exitcode = EXIT_FAILURE; 761 goto cleanup; 762 } 763 764 /* Allocate a buffer to store result string */ 765 resultstrlen = RESULTLEN; 766 if ((resultstr = malloc(resultstrlen)) == NULL) { 767 int err = errno; 768 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 769 strerror(err)); 770 exitcode = EXIT_FAILURE; 771 goto cleanup; 772 } 773 774 mech.mechanism = mech_type; 775 mech.pParameter = NULL_PTR; 776 mech.ulParameterLen = 0; 777 exitcode = EXIT_SUCCESS; 778 i = 0; 779 780 do { 781 if (filecount > 0 && filelist != NULL) { 782 filename = filelist[i]; 783 if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == 784 -1) { 785 cryptoerror(LOG_STDERR, gettext( 786 "can not open input file %s\n"), filename); 787 exitcode = EXIT_USAGE; 788 continue; 789 } 790 } else { 791 fd = 0; /* use stdin */ 792 } 793 794 /* 795 * Perform the operation 796 */ 797 if (mac_cmd) { 798 rv = do_mac(hSession, &mech, fd, key, &resultbuf, 799 &resultlen); 800 } else { 801 rv = do_digest(hSession, &mech, fd, &resultbuf, 802 &resultlen); 803 } 804 805 if (rv != CKR_OK) { 806 cryptoerror(LOG_STDERR, 807 gettext("crypto operation failed for " 808 "file %s: %s\n"), 809 filename ? filename : "STDIN", 810 pkcs11_strerror(rv)); 811 exitcode = EXIT_FAILURE; 812 continue; 813 } 814 815 /* if result size has changed, allocate a bigger resulstr buf */ 816 if (resultlen != RESULTLEN) { 817 resultstrlen = 2 * resultlen + 1; 818 resultstr = realloc(resultstr, resultstrlen); 819 820 if (resultstr == NULL) { 821 int err = errno; 822 cryptoerror(LOG_STDERR, 823 gettext("realloc: %s\n"), strerror(err)); 824 exitcode = EXIT_FAILURE; 825 goto cleanup; 826 } 827 } 828 829 /* Output the result */ 830 tohexstr(resultbuf, resultlen, resultstr, resultstrlen); 831 832 /* Include mechanism name for verbose */ 833 if (vflag) 834 (void) fprintf(stdout, "%s ", algo_str); 835 836 /* Include file name for multiple files, or if verbose */ 837 if (filecount > 1 || (vflag && filecount > 0)) { 838 (void) fprintf(stdout, "(%s) = ", filename); 839 } 840 841 (void) fprintf(stdout, "%s\n", resultstr); 842 (void) close(fd); 843 844 845 } while (++i < filecount); 846 847 848 /* clear and free the key */ 849 if (mac_cmd) { 850 (void) memset(pkeydata, 0, keylen); 851 free(pkeydata); 852 pkeydata = NULL; 853 } 854 855 cleanup: 856 if (resultbuf != NULL) { 857 free(resultbuf); 858 } 859 860 if (resultstr != NULL) { 861 free(resultstr); 862 } 863 864 if (pSlotList != NULL) { 865 free(pSlotList); 866 } 867 868 if (!Kflag && key != (CK_OBJECT_HANDLE) 0) { 869 (void) C_DestroyObject(hSession, key); 870 } 871 872 if (hSession != CK_INVALID_HANDLE) 873 (void) C_CloseSession(hSession); 874 875 (void) C_Finalize(NULL_PTR); 876 877 return (exitcode); 878 } 879 880 /* 881 * do_digest - Compute digest of a file 882 * 883 * hSession - session 884 * pmech - ptr to mechanism to be used for digest 885 * fd - file descriptor 886 * pdigest - buffer where digest result is returned 887 * pdigestlen - length of digest buffer on input, 888 * length of result on output 889 */ 890 static CK_RV 891 do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, 892 int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen) 893 { 894 CK_RV rv; 895 ssize_t nread; 896 int saved_errno; 897 898 if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) { 899 return (rv); 900 } 901 902 while ((nread = read(fd, buf, sizeof (buf))) > 0) { 903 /* Get the digest */ 904 rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread); 905 if (rv != CKR_OK) 906 return (rv); 907 } 908 909 saved_errno = errno; /* for later use */ 910 911 /* 912 * Perform the C_DigestFinal, even if there is a read error. 913 * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE 914 * next time it is called (for another file) 915 */ 916 917 rv = C_DigestFinal(hSession, *pdigest, pdigestlen); 918 919 /* result too big to fit? Allocate a bigger buffer */ 920 if (rv == CKR_BUFFER_TOO_SMALL) { 921 *pdigest = realloc(*pdigest, *pdigestlen); 922 923 if (*pdigest == NULL_PTR) { 924 int err = errno; 925 cryptoerror(LOG_STDERR, 926 gettext("realloc: %s\n"), strerror(err)); 927 return (CKR_HOST_MEMORY); 928 } 929 930 rv = C_DigestFinal(hSession, *pdigest, pdigestlen); 931 } 932 933 934 /* There was a read error */ 935 if (nread == -1) { 936 cryptoerror(LOG_STDERR, gettext( 937 "error reading file: %s"), strerror(saved_errno)); 938 return (CKR_GENERAL_ERROR); 939 } else { 940 return (rv); 941 } 942 } 943 944 /* 945 * do_mac - Compute mac of a file 946 * 947 * hSession - session 948 * pmech - ptr to mechanism to be used 949 * fd - file descriptor 950 * key - key to be used 951 * psignature - ptr buffer where mac result is returned 952 * returns new buf if current buf is small 953 * psignaturelen - length of mac buffer on input, 954 * length of result on output 955 */ 956 static CK_RV 957 do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, 958 int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature, 959 CK_ULONG_PTR psignaturelen) 960 { 961 CK_RV rv; 962 ssize_t nread; 963 int saved_errno; 964 965 if ((rv = C_SignInit(hSession, pmech, key)) != CKR_OK) { 966 return (rv); 967 } 968 969 while ((nread = read(fd, buf, sizeof (buf))) > 0) { 970 /* Get the MAC */ 971 rv = C_SignUpdate(hSession, buf, (CK_ULONG)nread); 972 if (rv != CKR_OK) 973 return (rv); 974 } 975 976 saved_errno = errno; /* for later use */ 977 978 /* 979 * Perform the C_SignFinal, even if there is a read error. 980 * Otherwise C_SignInit will return CKR_OPERATION_ACTIVE 981 * next time it is called (for another file) 982 */ 983 984 rv = C_SignFinal(hSession, *psignature, psignaturelen); 985 986 /* result too big to fit? Allocate a bigger buffer */ 987 if (rv == CKR_BUFFER_TOO_SMALL) { 988 *psignature = realloc(*psignature, *psignaturelen); 989 990 if (*psignature == NULL_PTR) { 991 int err = errno; 992 cryptoerror(LOG_STDERR, 993 gettext("realloc: %s\n"), strerror(err)); 994 return (CKR_HOST_MEMORY); 995 } 996 997 rv = C_SignFinal(hSession, *psignature, psignaturelen); 998 } 999 1000 /* There was a read error */ 1001 if (nread == -1) { 1002 cryptoerror(LOG_STDERR, gettext("error reading file: %s"), 1003 strerror(saved_errno)); 1004 return (CKR_GENERAL_ERROR); 1005 } else { 1006 return (rv); 1007 } 1008 } 1009 1010 1011 /* 1012 * getkey - gets keydata from file specified 1013 * 1014 * filename - name of file, if null, prompt for pass phrase 1015 * pkeydata - binary key data is returned in this buf 1016 * 1017 * returns length of key, or -1 if error 1018 */ 1019 static int 1020 getkey(char *filename, CK_BYTE_PTR *pkeydata) 1021 { 1022 struct stat statbuf; 1023 char *keybuf = NULL; 1024 char *tmpbuf; 1025 int keylen; 1026 int fd; 1027 1028 if (filename != NULL) { 1029 1030 /* read the key file into a buffer */ 1031 if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) { 1032 cryptoerror(LOG_STDERR, gettext( 1033 "can't open %s\n"), filename); 1034 return (-1); 1035 1036 } 1037 1038 if (fstat(fd, &statbuf) == -1) { 1039 cryptoerror(LOG_STDERR, gettext( 1040 "can't stat %s\n"), filename); 1041 (void) close(fd); 1042 return (-1); 1043 } 1044 1045 if (!S_ISREG(statbuf.st_mode)) { 1046 cryptoerror(LOG_STDERR, gettext( 1047 "%s not a regular file\n"), filename); 1048 (void) close(fd); 1049 return (-1); 1050 } 1051 1052 keylen = (size_t)statbuf.st_size; 1053 1054 if (keylen > 0) { 1055 /* allocate a buffer to hold the entire key */ 1056 if ((keybuf = malloc(keylen)) == NULL) { 1057 int err = errno; 1058 cryptoerror(LOG_STDERR, gettext("malloc: %s\n"), 1059 strerror(err)); 1060 (void) close(fd); 1061 return (-1); 1062 } 1063 1064 if (read(fd, keybuf, keylen) != keylen) { 1065 cryptoerror(LOG_STDERR, gettext( 1066 "can't read %s\n"), filename); 1067 (void) close(fd); 1068 return (-1); 1069 } 1070 } 1071 (void) close(fd); 1072 1073 } else { 1074 1075 /* No file, prompt for a pass phrase */ 1076 tmpbuf = getpassphrase(gettext("Enter key:")); 1077 1078 if (tmpbuf == NULL) { 1079 return (-1); /* error */ 1080 } else { 1081 keybuf = strdup(tmpbuf); 1082 (void) memset(tmpbuf, 0, strlen(tmpbuf)); 1083 } 1084 keylen = strlen(keybuf); 1085 } 1086 1087 *pkeydata = (CK_BYTE_PTR)keybuf; 1088 1089 return (keylen); 1090 } 1091 1092 static int 1093 getpasswd(char *token_spec, CK_BYTE_PTR *pdata, CK_ULONG *psize) 1094 { 1095 char *databuf; 1096 char *tmpbuf; 1097 char prompt[1024]; 1098 1099 if (token_spec == NULL) 1100 return (-1); 1101 1102 (void) snprintf(prompt, sizeof (prompt), DEFAULT_TOKEN_PROMPT, 1103 token_spec); 1104 tmpbuf = getpassphrase(gettext(prompt)); 1105 1106 if (tmpbuf == NULL) { 1107 return (-1); /* error */ 1108 } 1109 1110 databuf = strdup(tmpbuf); 1111 (void) memset(tmpbuf, 0, strlen(tmpbuf)); 1112 if (databuf == NULL) 1113 return (-1); 1114 1115 *pdata = (CK_BYTE_PTR)databuf; 1116 *psize = (CK_ULONG)strlen(databuf); 1117 1118 return (0); 1119 } 1120