summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-crypto/digest/digest.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/cmd-crypto/digest/digest.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/cmd-crypto/digest/digest.c')
-rw-r--r--usr/src/cmd/cmd-crypto/digest/digest.c935
1 files changed, 935 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-crypto/digest/digest.c b/usr/src/cmd/cmd-crypto/digest/digest.c
new file mode 100644
index 0000000000..0ee20b00d0
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/digest/digest.c
@@ -0,0 +1,935 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * digest.c
+ *
+ * Implements digest(1) and mac(1) commands
+ * If command name is mac, performs mac operation
+ * else perform digest operation
+ *
+ * See the man pages for digest and mac for details on
+ * how these commands work.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <strings.h>
+#include <libintl.h>
+#include <libgen.h>
+#include <locale.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <security/cryptoki.h>
+#include <limits.h>
+#include <cryptoutil.h>
+
+#define BUFFERSIZE (4096) /* Buffer size for reading file */
+
+/*
+ * RESULTLEN - large enough size in bytes to hold result for
+ * digest and mac results for all mechanisms
+ */
+#define RESULTLEN (512)
+
+/*
+ * Default parameters for PBKDF2 algorithm
+ */
+#define PBKD2_ITERATIONS (1000)
+#define PBKD2_SALT_SIZE 16
+
+/*
+ * Exit Status codes
+ */
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0 /* No errors */
+#define EXIT_FAILURE 1 /* All errors except usage */
+#endif /* EXIT_SUCCESS */
+
+#define EXIT_USAGE 2 /* usage/syntax error */
+
+#define MAC_NAME "mac" /* name of mac command */
+#define MAC_OPTIONS "lva:k:" /* for getopt */
+#define DIGEST_NAME "digest" /* name of mac command */
+#define DIGEST_OPTIONS "lva:" /* for getopt */
+
+static boolean_t vflag = B_FALSE; /* -v (verbose) flag, optional */
+static boolean_t aflag = B_FALSE; /* -a <algorithm> flag, required */
+static boolean_t lflag = B_FALSE; /* -l flag, for mac and digest */
+
+static char *keyfile = NULL; /* name of keyfile */
+static CK_BYTE buf[BUFFERSIZE];
+
+struct mech_alias {
+ CK_MECHANISM_TYPE type;
+ char *alias;
+ CK_ULONG keysize_min;
+ CK_ULONG keysize_max;
+ int keysize_unit;
+ boolean_t available;
+};
+
+#define MECH_ALIASES_COUNT 5
+
+static struct mech_alias mech_aliases[] = {
+ { CKM_SHA_1, "sha1", ULONG_MAX, 0L, 8, B_FALSE },
+ { CKM_MD5, "md5", ULONG_MAX, 0L, 8, B_FALSE },
+ { CKM_DES_MAC, "des_mac", ULONG_MAX, 0L, 8, B_FALSE },
+ { CKM_SHA_1_HMAC, "sha1_hmac", ULONG_MAX, 0L, 8, B_FALSE },
+ { CKM_MD5_HMAC, "md5_hmac", ULONG_MAX, 0L, 8, B_FALSE },
+};
+
+static CK_BBOOL true = TRUE;
+
+static void usage(boolean_t mac_cmd);
+static int execute_cmd(char *algo_str, int filecount,
+ char **filelist, boolean_t mac_cmd);
+static CK_RV do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
+ int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature,
+ CK_ULONG_PTR psignaturelen);
+static CK_RV do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
+ int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen);
+static int getkey(char *filename, CK_BYTE_PTR *pkeydata);
+
+int
+main(int argc, char **argv)
+{
+
+ extern char *optarg;
+ extern int optind;
+ int errflag = 0; /* We had an optstr parse error */
+ char c; /* current getopts flag */
+ char *algo_str; /* mechanism/algorithm string */
+ int filecount;
+ boolean_t mac_cmd; /* if TRUE, do mac, else do digest */
+ char *optstr;
+ char **filelist; /* list of files */
+ char *cmdname = NULL; /* name of command */
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defiend by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ /*
+ * Based on command name, determine
+ * type of command. mac is mac
+ * everything else is digest.
+ */
+ cmdname = basename(argv[0]);
+
+ cryptodebug_init(cmdname);
+
+ if (strcmp(cmdname, MAC_NAME) == 0)
+ mac_cmd = B_TRUE;
+ else if (strcmp(cmdname, DIGEST_NAME) == 0)
+ mac_cmd = B_FALSE;
+ else {
+ cryptoerror(LOG_STDERR, gettext(
+ "command name must be either digest or mac\n"));
+ exit(EXIT_USAGE);
+ }
+
+ if (mac_cmd) {
+ optstr = MAC_OPTIONS;
+ } else {
+ optstr = DIGEST_OPTIONS;
+ }
+
+ /* Parse command line arguments */
+ while (!errflag && (c = getopt(argc, argv, optstr)) != -1) {
+
+ switch (c) {
+ case 'v':
+ vflag = B_TRUE;
+ break;
+ case 'a':
+ aflag = B_TRUE;
+ algo_str = optarg;
+ break;
+ case 'k':
+ keyfile = optarg;
+ break;
+ case 'l':
+ lflag = B_TRUE;
+ break;
+ default:
+ errflag++;
+ }
+ }
+
+ filecount = argc - optind;
+ if (errflag || (!aflag && !lflag) || (lflag && argc > 2) ||
+ filecount < 0) {
+ usage(mac_cmd);
+ exit(EXIT_USAGE);
+ }
+
+ if (filecount == 0) {
+ filelist = NULL;
+ } else {
+ filelist = &argv[optind];
+ }
+
+ return (execute_cmd(algo_str, filecount, filelist, mac_cmd));
+}
+
+/*
+ * usage message for digest/mac
+ */
+static void
+usage(boolean_t mac_cmd)
+{
+ if (mac_cmd) {
+ cryptoerror(LOG_STDERR, gettext(
+ "usage: mac -l | [-v] -a <algorithm> [-k <keyfile>] "
+ "[file...]"));
+ } else {
+ cryptoerror(LOG_STDERR,
+ gettext("usage: digest -l | [-v] -a <algorithm> "
+ "[file...]"));
+ }
+}
+
+/*
+ * Print out list of available algorithms.
+ */
+static void
+algorithm_list(boolean_t mac_cmd)
+{
+ int mech;
+
+ if (mac_cmd)
+ (void) printf(gettext("Algorithm Keysize: Min "
+ "Max (bits)\n"
+ "------------------------------------------\n"));
+
+ for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) {
+
+ if (mech_aliases[mech].available == B_FALSE)
+ continue;
+
+ if (mac_cmd) {
+ (void) printf("%-15s", mech_aliases[mech].alias);
+
+ if (mech_aliases[mech].keysize_min != ULONG_MAX &&
+ mech_aliases[mech].keysize_max != 0)
+ (void) printf(" %5lu %5lu\n",
+ (mech_aliases[mech].keysize_min *
+ mech_aliases[mech].keysize_unit),
+ (mech_aliases[mech].keysize_max *
+ mech_aliases[mech].keysize_unit));
+ else
+ (void) printf("\n");
+
+ } else
+ (void) printf("%s\n", mech_aliases[mech].alias);
+
+ }
+}
+
+static CK_RV
+generate_pkcs5_key(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSaltData,
+ CK_ULONG saltLen,
+ CK_ULONG iterations,
+ CK_BYTE_PTR pkeydata, /* user entered passphrase */
+ CK_KEY_TYPE keytype,
+ CK_ULONG passwd_size,
+ CK_ULONG keylen, /* desired length of generated key */
+ CK_OBJECT_HANDLE *hKey)
+{
+ CK_RV rv;
+ CK_PKCS5_PBKD2_PARAMS params;
+ CK_MECHANISM mechanism;
+ CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+ CK_ATTRIBUTE tmpl[4];
+ int attrs = 0;
+
+ tmpl[attrs].type = CKA_CLASS;
+ tmpl[attrs].pValue = &class;
+ tmpl[attrs].ulValueLen = sizeof (class);
+ attrs++;
+
+ tmpl[attrs].type = CKA_KEY_TYPE;
+ tmpl[attrs].pValue = &keytype;
+ tmpl[attrs].ulValueLen = sizeof (keytype);
+ attrs++;
+
+ tmpl[attrs].type = CKA_SIGN;
+ tmpl[attrs].pValue = &true;
+ tmpl[attrs].ulValueLen = sizeof (CK_BBOOL);
+ attrs++;
+
+ if (keylen > 0) {
+ tmpl[attrs].type = CKA_VALUE_LEN;
+ tmpl[attrs].pValue = &keylen;
+ tmpl[attrs].ulValueLen = sizeof (keylen);
+ attrs++;
+ }
+
+ params.saltSource = CKZ_SALT_SPECIFIED;
+ params.pSaltSourceData = (void *)pSaltData;
+ params.ulSaltSourceDataLen = saltLen;
+ params.iterations = iterations;
+ params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
+ params.pPrfData = NULL;
+ params.ulPrfDataLen = 0;
+ params.pPassword = (CK_UTF8CHAR_PTR)pkeydata;
+ params.ulPasswordLen = &passwd_size;
+
+ mechanism.mechanism = CKM_PKCS5_PBKD2;
+ mechanism.pParameter = &params;
+ mechanism.ulParameterLen = sizeof (params);
+
+ rv = C_GenerateKey(hSession, &mechanism, tmpl,
+ attrs, hKey);
+
+ return (rv);
+}
+
+
+/*
+ * Execute the command.
+ * algo_str - name of algorithm
+ * filecount - no. of files to process, if 0, use stdin
+ * filelist - list of files
+ * mac_cmd - if true do mac else do digest
+ */
+static int
+execute_cmd(char *algo_str, int filecount, char **filelist, boolean_t mac_cmd)
+{
+ int fd;
+ char *filename = NULL;
+ CK_RV rv;
+ CK_ULONG slotcount;
+ CK_SLOT_ID slotID;
+ CK_SLOT_ID_PTR pSlotList = NULL;
+ CK_MECHANISM_TYPE mech_type;
+ CK_MECHANISM_INFO info;
+ CK_MECHANISM mech;
+ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
+ CK_BYTE_PTR resultbuf = NULL;
+ CK_ULONG resultlen;
+ CK_BYTE_PTR pkeydata = NULL;
+ CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0;
+ int keylen = 0; /* key length */
+ char *resultstr = NULL; /* result in hex string */
+ int resultstrlen; /* result string length */
+ int i;
+ int exitcode = EXIT_SUCCESS; /* return code */
+ int slot, mek; /* index variables */
+ int mech_match = 0;
+ CK_BYTE salt[PBKD2_SALT_SIZE];
+ CK_ULONG keysize;
+ CK_ULONG iterations = PBKD2_ITERATIONS;
+
+ if (aflag) {
+ /*
+ * Determine if algorithm/mechanism is valid
+ */
+ for (mech_match = 0; mech_match < MECH_ALIASES_COUNT;
+ mech_match++) {
+ if (strcmp(algo_str,
+ mech_aliases[mech_match].alias) == 0) {
+ mech_type = mech_aliases[mech_match].type;
+ break;
+ }
+
+ }
+
+ if (mech_match == MECH_ALIASES_COUNT) {
+ cryptoerror(LOG_STDERR,
+ gettext("unknown algorithm -- %s"), algo_str);
+ return (EXIT_FAILURE);
+ }
+
+ /* Get key to do a MAC operation */
+ if (mac_cmd) {
+ keylen = getkey(keyfile, &pkeydata);
+ if (keylen <= 0 || pkeydata == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("invalid key."));
+ return (EXIT_FAILURE);
+ }
+ }
+ }
+
+ /* Initialize, and get list of slots */
+ if ((rv = C_Initialize(NULL)) != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("failed to initialize PKCS #11 framework: %s"),
+ pkcs11_strerror(rv));
+ return (EXIT_FAILURE);
+ }
+
+ /* Get slot count */
+ rv = C_GetSlotList(0, NULL_PTR, &slotcount);
+ if (rv != CKR_OK || slotcount == 0) {
+ cryptoerror(LOG_STDERR, gettext(
+ "failed to find any cryptographic provider,"
+ "please check with your system administrator: %s"),
+ pkcs11_strerror(rv));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* Found at least one slot, allocate memory for slot list */
+ pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
+ if (pSlotList == NULL_PTR) {
+ int err = errno;
+ cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
+ strerror(err));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* Get the list of slots */
+ if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) {
+ cryptoerror(LOG_STDERR, gettext(
+ "failed to find any cryptographic provider,"
+ "please check with your system administrator: %s"),
+ pkcs11_strerror(rv));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /*
+ * Obtain list of algorithms if -l option was given
+ */
+ if (lflag) {
+
+ for (slot = 0; slot < slotcount; slot++) {
+
+ /* Iterate through each mechanism */
+ for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) {
+ rv = C_GetMechanismInfo(pSlotList[slot],
+ mech_aliases[mek].type, &info);
+
+ /* Only check algorithms that can be used */
+ if ((rv != CKR_OK) ||
+ (!mac_cmd && (info.flags & CKF_SIGN)) ||
+ (mac_cmd && (info.flags & CKF_DIGEST)))
+ continue;
+
+ /*
+ * Set to minimum/maximum key sizes assuming
+ * the values available are not 0.
+ */
+ if (info.ulMinKeySize && (info.ulMinKeySize <
+ mech_aliases[mek].keysize_min))
+ mech_aliases[mek].keysize_min =
+ info.ulMinKeySize;
+
+ if (info.ulMaxKeySize && (info.ulMaxKeySize >
+ mech_aliases[mek].keysize_max))
+ mech_aliases[mek].keysize_max =
+ info.ulMaxKeySize;
+
+ mech_aliases[mek].available = B_TRUE;
+ }
+
+ }
+
+ algorithm_list(mac_cmd);
+
+ goto cleanup;
+ }
+
+ /* Find a slot with matching mechanism */
+ for (i = 0; i < slotcount; i++) {
+ slotID = pSlotList[i];
+ rv = C_GetMechanismInfo(slotID, mech_type, &info);
+ if (rv != CKR_OK) {
+ continue; /* to the next slot */
+ } else {
+ if (mac_cmd) {
+ /*
+ * Make sure the slot supports
+ * PKCS5 key generation if we
+ * will be using it later.
+ * We use it whenever the key
+ * is entered at command line.
+ */
+ if ((info.flags & CKF_SIGN) &&
+ (keyfile == NULL)) {
+ CK_MECHANISM_INFO kg_info;
+ rv = C_GetMechanismInfo(slotID,
+ CKM_PKCS5_PBKD2, &kg_info);
+ if (rv == CKR_OK)
+ break;
+ } else if (info.flags & CKF_SIGN) {
+ break;
+ }
+ } else {
+ if (info.flags & CKF_DIGEST)
+ break;
+ }
+ }
+ }
+
+ /* Show error if no matching mechanism found */
+ if (i == slotcount) {
+ cryptoerror(LOG_STDERR,
+ gettext("no cryptographic provider was "
+ "found for this algorithm -- %s"), algo_str);
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* Mechanism is supported. Go ahead & open a session */
+ rv = C_OpenSession(slotID, CKF_SERIAL_SESSION,
+ NULL_PTR, NULL, &hSession);
+
+ if (rv != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("can not open PKCS#11 session: %s"),
+ pkcs11_strerror(rv));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* Create a key object for mac operation */
+ if (mac_cmd) {
+ /*
+ * If we read keybytes from a file,
+ * do NOT process them with C_GenerateKey,
+ * treat them as raw keydata bytes and
+ * create a key object for them.
+ */
+ if (keyfile) {
+ CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+ CK_KEY_TYPE tmpl_keytype = CKK_GENERIC_SECRET;
+ CK_BBOOL false = FALSE;
+ int nattr = 0;
+ CK_ATTRIBUTE template[5];
+
+ if (mech_type == CKM_DES_MAC) {
+ tmpl_keytype = CKK_DES;
+ }
+ template[nattr].type = CKA_CLASS;
+ template[nattr].pValue = &class;
+ template[nattr].ulValueLen = sizeof (class);
+ nattr++;
+
+ template[nattr].type = CKA_KEY_TYPE;
+ template[nattr].pValue = &tmpl_keytype;
+ template[nattr].ulValueLen = sizeof (tmpl_keytype);
+ nattr++;
+
+ template[nattr].type = CKA_SIGN;
+ template[nattr].pValue = &true;
+ template[nattr].ulValueLen = sizeof (true);
+ nattr++;
+
+ template[nattr].type = CKA_TOKEN;
+ template[nattr].pValue = &false;
+ template[nattr].ulValueLen = sizeof (false);
+ nattr++;
+
+ template[nattr].type = CKA_VALUE;
+ template[nattr].pValue = pkeydata;
+ template[nattr].ulValueLen = keylen;
+ nattr++;
+
+ rv = C_CreateObject(hSession, template,
+ nattr, &key);
+ } else {
+ CK_KEY_TYPE keytype;
+ if (mech_type == CKM_DES_MAC) {
+ keytype = CKK_DES;
+ keysize = 0;
+ } else {
+ keytype = CKK_GENERIC_SECRET;
+ keysize = 16; /* 128 bits */
+ }
+ /*
+ * We use a fixed salt (0x0a, 0x0a, 0x0a ...)
+ * for creating the key so that the end user
+ * will be able to generate the same 'mac'
+ * using the same passphrase.
+ */
+ (void) memset(salt, 0x0a, sizeof (salt));
+ rv = generate_pkcs5_key(hSession,
+ salt, sizeof (salt),
+ iterations, pkeydata,
+ keytype, keylen, keysize,
+ &key);
+ }
+
+ if (rv != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("unable to create key for crypto "
+ "operation: %s"), pkcs11_strerror(rv));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ /* Allocate a buffer to store result. */
+ resultlen = RESULTLEN;
+ if ((resultbuf = malloc(resultlen)) == NULL) {
+ int err = errno;
+ cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
+ strerror(err));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* Allocate a buffer to store result string */
+ resultstrlen = RESULTLEN;
+ if ((resultstr = malloc(resultstrlen)) == NULL) {
+ int err = errno;
+ cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
+ strerror(err));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ mech.mechanism = mech_type;
+ mech.pParameter = NULL_PTR;
+ mech.ulParameterLen = 0;
+ exitcode = EXIT_SUCCESS;
+ i = 0;
+
+ do {
+ if (filecount > 0 && filelist != NULL) {
+ filename = filelist[i];
+ if ((fd = open(filename, O_RDONLY
+ | O_NONBLOCK)) == -1) {
+ cryptoerror(LOG_STDERR, gettext(
+ "can not open input file %s\n"), filename);
+ exitcode = EXIT_USAGE;
+ continue;
+ }
+ } else {
+ fd = 0; /* use stdin */
+ }
+
+ /*
+ * Perform the operation
+ */
+ if (mac_cmd) {
+ rv = do_mac(hSession, &mech, fd, key, &resultbuf,
+ &resultlen);
+ } else {
+ rv = do_digest(hSession, &mech, fd, &resultbuf,
+ &resultlen);
+ }
+
+ if (rv != CKR_OK) {
+ cryptoerror(LOG_STDERR,
+ gettext("crypto operation failed for "
+ "file %s: %s\n"),
+ filename ? filename : "STDIN",
+ pkcs11_strerror(rv));
+ exitcode = EXIT_FAILURE;
+ continue;
+ }
+
+ /* if result size has changed, allocate a bigger resulstr buf */
+ if (resultlen != RESULTLEN) {
+ resultstrlen = 2 * resultlen + 1;
+ resultstr = realloc(resultstr, resultstrlen);
+
+ if (resultstr == NULL) {
+ int err = errno;
+ cryptoerror(LOG_STDERR,
+ gettext("realloc: %s\n"), strerror(err));
+ exitcode = EXIT_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ /* Output the result */
+ tohexstr(resultbuf, resultlen, resultstr, resultstrlen);
+
+ /* Include mechanism name for verbose */
+ if (vflag)
+ (void) fprintf(stdout, "%s ", algo_str);
+
+ /* Include file name for multiple files, or if verbose */
+ if (filecount > 1 || (vflag && filecount > 0)) {
+ (void) fprintf(stdout, "(%s) = ", filename);
+ }
+
+ (void) fprintf(stdout, "%s\n", resultstr);
+ (void) close(fd);
+
+
+ } while (++i < filecount);
+
+
+ /* clear and free the key */
+ if (mac_cmd) {
+ (void) memset(pkeydata, 0, keylen);
+ free(pkeydata);
+ pkeydata = NULL;
+ }
+
+cleanup:
+ if (resultbuf != NULL) {
+ free(resultbuf);
+ }
+
+ if (resultstr != NULL) {
+ free(resultstr);
+ }
+
+ if (pSlotList != NULL) {
+ free(pSlotList);
+ }
+
+ if (key != (CK_OBJECT_HANDLE) 0) {
+ (void) C_DestroyObject(hSession, key);
+ }
+
+ if (hSession != CK_INVALID_HANDLE)
+ (void) C_CloseSession(hSession);
+
+ (void) C_Finalize(NULL_PTR);
+
+ return (exitcode);
+}
+
+/*
+ * do_digest - Compute digest of a file
+ *
+ * hSession - session
+ * pmech - ptr to mechanism to be used for digest
+ * fd - file descriptor
+ * pdigest - buffer where digest result is returned
+ * pdigestlen - length of digest buffer on input,
+ * length of result on output
+ */
+static CK_RV
+do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
+ int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen)
+{
+ CK_RV rv;
+ ssize_t nread;
+ int saved_errno;
+
+ if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) {
+ return (rv);
+ }
+
+ while ((nread = read(fd, buf, sizeof (buf))) > 0) {
+ /* Get the digest */
+ rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread);
+ if (rv != CKR_OK)
+ return (rv);
+ }
+
+ saved_errno = errno; /* for later use */
+
+ /*
+ * Perform the C_DigestFinal, even if there is a read error.
+ * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE
+ * next time it is called (for another file)
+ */
+
+ rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
+
+ /* result too big to fit? Allocate a bigger buffer */
+ if (rv == CKR_BUFFER_TOO_SMALL) {
+ *pdigest = realloc(*pdigest, *pdigestlen);
+
+ if (*pdigest == NULL_PTR) {
+ int err = errno;
+ cryptoerror(LOG_STDERR,
+ gettext("realloc: %s\n"), strerror(err));
+ return (CKR_HOST_MEMORY);
+ }
+
+ rv = C_DigestFinal(hSession, *pdigest, pdigestlen);
+ }
+
+
+ /* There was a read error */
+ if (nread == -1) {
+ cryptoerror(LOG_STDERR, gettext(
+ "error reading file: %s"), strerror(saved_errno));
+ return (CKR_GENERAL_ERROR);
+ } else {
+ return (rv);
+ }
+}
+
+/*
+ * do_mac - Compute mac of a file
+ *
+ * hSession - session
+ * pmech - ptr to mechanism to be used
+ * fd - file descriptor
+ * key - key to be used
+ * psignature - ptr buffer where mac result is returned
+ * returns new buf if current buf is small
+ * psignaturelen - length of mac buffer on input,
+ * length of result on output
+ */
+static CK_RV
+do_mac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech,
+ int fd, CK_OBJECT_HANDLE key, CK_BYTE_PTR *psignature,
+ CK_ULONG_PTR psignaturelen)
+{
+ CK_RV rv;
+ ssize_t nread;
+ int saved_errno;
+
+ if ((rv = C_SignInit(hSession, pmech, key)) != CKR_OK) {
+ return (rv);
+ }
+
+ while ((nread = read(fd, buf, sizeof (buf))) > 0) {
+ /* Get the MAC */
+ rv = C_SignUpdate(hSession, buf, (CK_ULONG)nread);
+ if (rv != CKR_OK)
+ return (rv);
+ }
+
+ saved_errno = errno; /* for later use */
+
+ /*
+ * Perform the C_SignFinal, even if there is a read error.
+ * Otherwise C_SignInit will return CKR_OPERATION_ACTIVE
+ * next time it is called (for another file)
+ */
+
+ rv = C_SignFinal(hSession, *psignature, psignaturelen);
+
+ /* result too big to fit? Allocate a bigger buffer */
+ if (rv == CKR_BUFFER_TOO_SMALL) {
+ *psignature = realloc(*psignature, *psignaturelen);
+
+ if (*psignature == NULL_PTR) {
+ int err = errno;
+ cryptoerror(LOG_STDERR,
+ gettext("realloc: %s\n"), strerror(err));
+ return (CKR_HOST_MEMORY);
+ }
+
+ rv = C_SignFinal(hSession, *psignature, psignaturelen);
+ }
+
+ /* There was a read error */
+ if (nread == -1) {
+ cryptoerror(LOG_STDERR, gettext("error reading file: %s"),
+ strerror(saved_errno));
+ return (CKR_GENERAL_ERROR);
+ } else {
+ return (rv);
+ }
+}
+
+
+/*
+ * getkey - gets keydata from file specified
+ *
+ * filename - name of file, if null, prompt for pass phrase
+ * pkeydata - binary key data is returned in this buf
+ *
+ * returns length of key, or -1 if error
+ */
+static int
+getkey(char *filename, CK_BYTE_PTR *pkeydata)
+{
+ struct stat statbuf;
+ char *keybuf = NULL;
+ char *tmpbuf;
+ int keylen;
+ int fd;
+
+ if (filename != NULL) {
+
+ /* read the key file into a buffer */
+ if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) {
+ cryptoerror(LOG_STDERR, gettext(
+ "can't open %s\n"), filename);
+ return (-1);
+
+ }
+
+ if (fstat(fd, &statbuf) == -1) {
+ cryptoerror(LOG_STDERR, gettext(
+ "can't stat %s\n"), filename);
+ (void) close(fd);
+ return (-1);
+ }
+
+ if (!(statbuf.st_mode & S_IFREG)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "%s not a regular file\n"), filename);
+ (void) close(fd);
+ return (-1);
+ }
+
+ keylen = (size_t)statbuf.st_size;
+
+ if (keylen > 0) {
+ /* allocate a buffer to hold the entire key */
+ if ((keybuf = malloc(keylen)) == NULL) {
+ int err = errno;
+ cryptoerror(LOG_STDERR, gettext("malloc: %s\n"),
+ strerror(err));
+ (void) close(fd);
+ return (-1);
+ }
+
+ if (read(fd, keybuf, keylen) != keylen) {
+ cryptoerror(LOG_STDERR, gettext(
+ "can't read %s\n"), filename);
+ (void) close(fd);
+ return (-1);
+ }
+ }
+ (void) close(fd);
+
+ } else {
+
+ /* No file, prompt for a pass phrase */
+ tmpbuf = getpassphrase(gettext("Enter key:"));
+
+ if (tmpbuf == NULL) {
+ return (-1); /* error */
+ } else {
+ keybuf = strdup(tmpbuf);
+ (void) memset(tmpbuf, 0, strlen(tmpbuf));
+ }
+ keylen = strlen(keybuf);
+ }
+
+ *pkeydata = (CK_BYTE_PTR)keybuf;
+
+ return (keylen);
+}