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