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