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