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