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