#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <strings.h>
#include <libintl.h>
#include <libgen.h>
#include <locale.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <security/cryptoki.h>
#include <cryptoutil.h>
#include <kmfapi.h>
#define BUFFERSIZE (1024 * 64)
#define BLOCKSIZE (128)
#define PROGRESSSIZE (1024 * 40)
#define SUNW_ENCRYPT_FILE_VERSION 1
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#endif
#define EXIT_USAGE 2
#define ENCRYPT_NAME "encrypt"
#define ENCRYPT_OPTIONS "a:T:K:k:i:o:lv"
#define DECRYPT_NAME "decrypt"
#define DECRYPT_OPTIONS "a:T:K:k:i:o:lv"
struct CommandInfo {
char *name;
char *options;
CK_FLAGS flags;
CK_ATTRIBUTE_TYPE type;
CK_RV (*Init)(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE);
CK_RV (*Update)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
CK_ULONG_PTR);
CK_RV (*Crypt)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
CK_ULONG_PTR);
CK_RV (*Final)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR);
};
static struct CommandInfo encrypt_cmd = {
ENCRYPT_NAME,
ENCRYPT_OPTIONS,
CKF_ENCRYPT,
CKA_ENCRYPT,
C_EncryptInit,
C_EncryptUpdate,
C_Encrypt,
C_EncryptFinal
};
static struct CommandInfo decrypt_cmd = {
DECRYPT_NAME,
DECRYPT_OPTIONS,
CKF_DECRYPT,
CKA_DECRYPT,
C_DecryptInit,
C_DecryptUpdate,
C_Decrypt,
C_DecryptFinal
};
struct mech_alias {
CK_MECHANISM_TYPE type;
char *alias;
CK_ULONG keysize_min;
CK_ULONG keysize_max;
int keysize_unit;
int ivlen;
boolean_t available;
};
#define MECH_ALIASES_COUNT 4
static struct mech_alias mech_aliases[] = {
{ CKM_AES_CBC_PAD, "aes", ULONG_MAX, 0L, 8, 16, B_FALSE },
{ CKM_RC4, "arcfour", ULONG_MAX, 0L, 1, 0, B_FALSE },
{ CKM_DES_CBC_PAD, "des", 8, 8, 8, 8, B_FALSE },
{ CKM_DES3_CBC_PAD, "3des", 24, 24, 8, 8, B_FALSE },
};
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
static boolean_t aflag = B_FALSE;
static boolean_t kflag = B_FALSE;
static boolean_t iflag = B_FALSE;
static boolean_t oflag = B_FALSE;
static boolean_t lflag = B_FALSE;
static boolean_t vflag = B_FALSE;
static boolean_t Tflag = B_FALSE;
static boolean_t Kflag = B_FALSE;
static char *keyfile = NULL;
static char *inputfile = NULL;
static char *outputfile = NULL;
static char *token_label = NULL;
static char *key_label = NULL;
static int status_pos = 0;
static void usage(struct CommandInfo *cmd);
static int execute_cmd(struct CommandInfo *cmd, char *algo_str);
static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession,
int infd, int outfd, off_t insize);
int
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
char *optstr;
int c;
char *algo_str = NULL;
struct CommandInfo *cmd;
char *cmdname;
boolean_t errflag = B_FALSE;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
cmdname = basename(argv[0]);
cryptodebug_init(cmdname);
if (strcmp(cmdname, encrypt_cmd.name) == 0) {
cmd = &encrypt_cmd;
} else if (strcmp(cmdname, decrypt_cmd.name) == 0) {
cmd = &decrypt_cmd;
} else {
cryptoerror(LOG_STDERR, gettext(
"command name must be either encrypt or decrypt"));
exit(EXIT_USAGE);
}
optstr = cmd->options;
while (!errflag && (c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
case 'a':
aflag = B_TRUE;
algo_str = optarg;
break;
case 'k':
kflag = B_TRUE;
keyfile = optarg;
break;
case 'T':
Tflag = B_TRUE;
token_label = optarg;
break;
case 'K':
Kflag = B_TRUE;
key_label = optarg;
break;
case 'i':
iflag = B_TRUE;
inputfile = optarg;
break;
case 'o':
oflag = B_TRUE;
outputfile = optarg;
break;
case 'l':
lflag = B_TRUE;
break;
case 'v':
vflag = B_TRUE;
break;
default:
errflag = B_TRUE;
}
}
if (errflag || (!aflag && !lflag) || (lflag && argc > 2) ||
(kflag && Kflag) || (Tflag && !Kflag) ||
(optind < argc)) {
usage(cmd);
exit(EXIT_USAGE);
}
return (execute_cmd(cmd, algo_str));
}
static void
usage(struct CommandInfo *cmd)
{
(void) fprintf(stderr, gettext("Usage:\n"));
if (cmd->type == CKA_ENCRYPT) {
(void) fprintf(stderr, gettext(" encrypt -l\n"));
(void) fprintf(stderr, gettext(" encrypt -a <algorithm> "
"[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
"[-i <infile>] [-o <outfile>]\n"));
} else {
(void) fprintf(stderr, gettext(" decrypt -l\n"));
(void) fprintf(stderr, gettext(" decrypt -a <algorithm> "
"[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
"[-i <infile>] [-o <outfile>]\n"));
}
}
static void
algorithm_list()
{
int mech;
(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;
(void) printf("%-15s", mech_aliases[mech].alias);
if (mech_aliases[mech].keysize_min != UINT_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");
}
}
static int
get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype,
char *keylabel, CK_BYTE *password, int password_len,
CK_OBJECT_HANDLE *keyobj)
{
CK_RV rv;
CK_ATTRIBUTE pTmpl[10];
CK_OBJECT_CLASS class = CKO_SECRET_KEY;
CK_BBOOL true = 1;
CK_BBOOL is_token = 1;
CK_ULONG key_obj_count = 1;
int i;
CK_KEY_TYPE ckKeyType = keytype;
rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password,
(CK_ULONG)password_len);
if (rv != CKR_OK) {
(void) fprintf(stderr, "Cannot login to the token."
" error = %s\n", pkcs11_strerror(rv));
return (-1);
}
i = 0;
pTmpl[i].type = CKA_TOKEN;
pTmpl[i].pValue = &is_token;
pTmpl[i].ulValueLen = sizeof (CK_BBOOL);
i++;
pTmpl[i].type = CKA_CLASS;
pTmpl[i].pValue = &class;
pTmpl[i].ulValueLen = sizeof (class);
i++;
pTmpl[i].type = CKA_LABEL;
pTmpl[i].pValue = keylabel;
pTmpl[i].ulValueLen = strlen(keylabel);
i++;
pTmpl[i].type = CKA_KEY_TYPE;
pTmpl[i].pValue = &ckKeyType;
pTmpl[i].ulValueLen = sizeof (ckKeyType);
i++;
pTmpl[i].type = CKA_PRIVATE;
pTmpl[i].pValue = &true;
pTmpl[i].ulValueLen = sizeof (true);
i++;
rv = C_FindObjectsInit(hSession, pTmpl, i);
if (rv != CKR_OK) {
goto out;
}
rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count);
(void) C_FindObjectsFinal(hSession);
out:
if (rv != CKR_OK) {
(void) fprintf(stderr,
"Cannot retrieve key object. error = %s\n",
pkcs11_strerror(rv));
return (-1);
}
if (key_obj_count == 0) {
(void) fprintf(stderr, "Cannot find the key object.\n");
return (-1);
}
return (0);
}
static int
execute_cmd(struct CommandInfo *cmd, char *algo_str)
{
CK_RV rv;
CK_ULONG slotcount;
CK_SLOT_ID slotID;
CK_SLOT_ID_PTR pSlotList = NULL;
CK_MECHANISM_TYPE mech_type = 0;
CK_MECHANISM_INFO info, kg_info;
CK_MECHANISM mech;
CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
CK_BYTE_PTR pkeydata = NULL;
CK_BYTE salt[CK_PKCS5_PBKD2_SALT_SIZE];
CK_ULONG keysize = 0;
int i, slot, mek;
int status;
struct stat insbuf;
struct stat outsbuf;
char tmpnam[PATH_MAX];
CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0;
int infd = 0;
int outfd = 1;
char *outfilename = NULL;
boolean_t errflag = B_TRUE;
boolean_t inoutsame = B_FALSE;
boolean_t leavefilealone = B_FALSE;
CK_BYTE_PTR pivbuf = NULL_PTR;
CK_ULONG ivlen = 0L;
int mech_match = 0;
uint32_t iterations = CK_PKCS5_PBKD2_ITERATIONS;
CK_ULONG keylen;
uint32_t version = SUNW_ENCRYPT_FILE_VERSION;
CK_KEY_TYPE keytype;
KMF_RETURN kmfrv;
CK_SLOT_ID token_slot_id;
if (aflag) {
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);
}
if (Kflag) {
if (token_label == NULL || !strlen(token_label)) {
token_label = pkcs11_default_token();
}
status = pkcs11_get_pass(token_label,
(char **)&pkeydata, (size_t *)&keysize, 0, B_FALSE);
} else if (kflag) {
status = pkcs11_read_data(keyfile, (void **)&pkeydata,
(size_t *)&keysize);
} else {
status = pkcs11_get_pass(NULL, (char **)&pkeydata,
(size_t *)&keysize, 0,
(cmd->type == CKA_ENCRYPT) ? B_TRUE : B_FALSE);
}
if (status != 0 || keysize == 0L) {
cryptoerror(LOG_STDERR,
kflag ? gettext("invalid key.") :
gettext("invalid passphrase."));
return (EXIT_FAILURE);
}
}
bzero(salt, sizeof (salt));
rv = C_Initialize(NULL);
if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
cryptoerror(LOG_STDERR, gettext("failed to initialize "
"PKCS #11 framework: %s"), pkcs11_strerror(rv));
goto cleanup;
}
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));
goto cleanup;
}
pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID));
if (pSlotList == NULL_PTR) {
int err = errno;
cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err));
goto cleanup;
}
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));
goto cleanup;
}
if (lflag) {
for (slot = 0; slot < slotcount; slot++) {
for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) {
rv = C_GetMechanismInfo(pSlotList[slot],
mech_aliases[mek].type, &info);
if (rv != CKR_OK)
continue;
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();
errflag = B_FALSE;
goto cleanup;
}
i = 0;
if (Kflag) {
kmfrv = kmf_pk11_token_lookup(NULL, token_label,
&token_slot_id);
if (kmfrv != KMF_OK) {
cryptoerror(LOG_STDERR,
gettext("no matching PKCS#11 token"));
errflag = B_TRUE;
goto cleanup;
}
rv = C_GetMechanismInfo(token_slot_id, mech_type, &info);
if (rv == CKR_OK && (info.flags & cmd->flags))
slotID = token_slot_id;
else
i = slotcount;
} else {
for (i = 0; i < slotcount; i++) {
slotID = pSlotList[i];
rv = C_GetMechanismInfo(slotID, mech_type, &info);
if (rv != CKR_OK) {
continue;
} else {
if ((info.flags & cmd->flags) &&
(mech_type == CKM_RC4) ||
(keyfile == NULL)) {
rv = C_GetMechanismInfo(slotID,
CKM_PKCS5_PBKD2, &kg_info);
if (rv == CKR_OK)
break;
} else if (info.flags & cmd->flags) {
break;
}
}
}
}
if (i == slotcount) {
cryptoerror(LOG_STDERR,
gettext("no cryptographic provider was "
"found for this algorithm -- %s"), algo_str);
goto cleanup;
}
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));
goto cleanup;
}
ivlen = mech_aliases[mech_match].ivlen;
if ((pivbuf = malloc((size_t)ivlen)) == NULL) {
int err = errno;
cryptoerror(LOG_STDERR, gettext("malloc: %s"),
strerror(err));
goto cleanup;
}
if (cmd->type == CKA_ENCRYPT) {
if ((pkcs11_get_urandom((void *)pivbuf,
mech_aliases[mech_match].ivlen)) != 0) {
cryptoerror(LOG_STDERR, gettext(
"Unable to generate random "
"data for initialization vector."));
goto cleanup;
}
}
rv = pkcs11_mech2keytype(mech_type, &keytype);
if (rv != CKR_OK) {
cryptoerror(LOG_STDERR,
gettext("unable to find key type for algorithm."));
goto cleanup;
}
if (iflag) {
if ((infd = open(inputfile, O_RDONLY | O_NONBLOCK)) == -1) {
cryptoerror(LOG_STDERR, gettext(
"can not open input file %s"), inputfile);
goto cleanup;
}
if (fstat(infd, &insbuf) == -1) {
cryptoerror(LOG_STDERR, gettext(
"can not stat input file %s"), inputfile);
goto cleanup;
}
}
inoutsame = B_FALSE;
if (oflag) {
outfilename = outputfile;
if ((stat(outputfile, &outsbuf) != -1) &&
(insbuf.st_ino == outsbuf.st_ino)) {
char *dir;
dir = dirname(outputfile);
(void) snprintf(tmpnam, sizeof (tmpnam),
"%s/encrXXXXXX", dir);
outfilename = tmpnam;
if ((outfd = mkstemp(tmpnam)) == -1) {
cryptoerror(LOG_STDERR, gettext(
"cannot create temp file"));
goto cleanup;
}
inoutsame = B_TRUE;
} else {
if ((outfd = open(outfilename,
O_CREAT|O_WRONLY|O_TRUNC, 0644)) == -1) {
cryptoerror(LOG_STDERR, gettext(
"cannot open output file %s"),
outfilename);
leavefilealone = B_TRUE;
goto cleanup;
}
}
}
if (cmd->type == CKA_DECRYPT) {
if (read(infd, &version, sizeof (version)) !=
sizeof (version)) {
cryptoerror(LOG_STDERR, gettext(
"failed to get format version from "
"input file."));
goto cleanup;
}
version = ntohl(version);
switch (version) {
case 1:
if (read(infd, &iterations,
sizeof (iterations)) != sizeof (iterations)) {
cryptoerror(LOG_STDERR, gettext(
"failed to get iterations from "
"input file."));
goto cleanup;
}
iterations = ntohl(iterations);
if (ivlen > 0 &&
read(infd, pivbuf, ivlen) != ivlen) {
cryptoerror(LOG_STDERR, gettext(
"failed to get initialization "
"vector from input file."));
goto cleanup;
}
if (read(infd, salt, sizeof (salt))
!= sizeof (salt)) {
cryptoerror(LOG_STDERR, gettext(
"failed to get salt data from "
"input file."));
goto cleanup;
}
break;
default:
cryptoerror(LOG_STDERR, gettext(
"Unrecognized format version read from "
"input file - expected %d, got %d."),
SUNW_ENCRYPT_FILE_VERSION, version);
goto cleanup;
}
}
if (Kflag) {
rv = get_token_key(hSession, keytype, key_label, pkeydata,
keysize, &key);
if (rv != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Can not find the token key"));
goto cleanup;
} else {
goto do_crypto;
}
} else if (cmd->type == CKA_ENCRYPT) {
rv = pkcs11_get_urandom((void *)salt, sizeof (salt));
if (rv != 0) {
cryptoerror(LOG_STDERR,
gettext("unable to generate random "
"data for key salt."));
goto cleanup;
}
}
if (kflag && keyfile != NULL && keytype != CKK_RC4) {
CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
CK_ATTRIBUTE template[5];
int nattr = 0;
template[nattr].type = CKA_CLASS;
template[nattr].pValue = &objclass;
template[nattr].ulValueLen = sizeof (objclass);
nattr++;
template[nattr].type = CKA_KEY_TYPE;
template[nattr].pValue = &keytype;
template[nattr].ulValueLen = sizeof (keytype);
nattr++;
template[nattr].type = cmd->type;
template[nattr].pValue = &truevalue;
template[nattr].ulValueLen = sizeof (truevalue);
nattr++;
template[nattr].type = CKA_TOKEN;
template[nattr].pValue = &falsevalue;
template[nattr].ulValueLen = sizeof (falsevalue);
nattr++;
template[nattr].type = CKA_VALUE;
template[nattr].pValue = pkeydata;
template[nattr].ulValueLen = keysize;
nattr++;
rv = C_CreateObject(hSession, template, nattr, &key);
} else {
if (keytype == CKK_DES || keytype == CKK_DES3)
keylen = 0;
else
keylen = 16;
rv = pkcs11_PasswdToPBKD2Object(hSession, (char *)pkeydata,
(size_t)keysize, (void *)salt, sizeof (salt), iterations,
keytype, keylen, cmd->flags, &key);
}
if (rv != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"failed to generate a key: %s"),
pkcs11_strerror(rv));
goto cleanup;
}
do_crypto:
mech.mechanism = mech_type;
mech.pParameter = (CK_VOID_PTR)pivbuf;
mech.ulParameterLen = ivlen;
if ((rv = cmd->Init(hSession, &mech, key)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"failed to initialize crypto operation: %s"),
pkcs11_strerror(rv));
goto cleanup;
}
if (cmd->type == CKA_ENCRYPT) {
uint32_t netversion = htonl(version);
uint32_t netiter;
if (write(outfd, &netversion, sizeof (netversion))
!= sizeof (netversion)) {
cryptoerror(LOG_STDERR, gettext(
"failed to write version number "
"to output file."));
goto cleanup;
}
netiter = htonl(iterations);
if (write(outfd, &netiter,
sizeof (netiter)) != sizeof (netiter)) {
cryptoerror(LOG_STDERR, gettext(
"failed to write iterations to output"));
goto cleanup;
}
if (ivlen > 0 && write(outfd, pivbuf, ivlen) != ivlen) {
cryptoerror(LOG_STDERR, gettext(
"failed to write initialization vector "
"to output"));
goto cleanup;
}
if (write(outfd, salt, sizeof (salt)) != sizeof (salt)) {
cryptoerror(LOG_STDERR, gettext(
"failed to write salt data to output"));
goto cleanup;
}
}
if (crypt_multipart(cmd, hSession, infd, outfd, insbuf.st_size) == -1) {
goto cleanup;
}
errflag = B_FALSE;
cleanup:
if (pkeydata != NULL) {
bzero(pkeydata, keysize);
free(pkeydata);
pkeydata = NULL;
}
if (Kflag != B_FALSE && key != (CK_OBJECT_HANDLE) 0) {
(void) C_DestroyObject(hSession, key);
}
if (pSlotList != NULL)
free(pSlotList);
if (pivbuf != NULL)
free(pivbuf);
if (iflag && (infd != -1))
(void) close(infd);
if (oflag && (outfd != -1))
(void) close(outfd);
if (inoutsame) {
if (rename(outfilename, inputfile) == -1) {
(void) unlink(outfilename);
cryptoerror(LOG_STDERR, gettext("rename failed."));
}
}
if (errflag && (outfilename != NULL) && !leavefilealone) {
(void) unlink(outfilename);
}
if (hSession != CK_INVALID_HANDLE)
(void) C_CloseSession(hSession);
(void) C_Finalize(NULL);
return (errflag);
}
static void
print_status(int pos_to_advance)
{
while (pos_to_advance > 0) {
switch (status_pos) {
case 0:
(void) fprintf(stderr, gettext("["));
break;
case 19:
case 39:
case 59:
(void) fprintf(stderr, gettext("|"));
break;
default:
(void) fprintf(stderr, gettext("."));
}
pos_to_advance--;
status_pos++;
}
}
static int
crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession,
int infd, int outfd, off_t insize)
{
CK_RV rv;
CK_ULONG resultlen;
CK_ULONG resultbuflen;
CK_BYTE_PTR resultbuf;
CK_ULONG datalen;
CK_BYTE databuf[BUFFERSIZE];
CK_BYTE outbuf[BUFFERSIZE+BLOCKSIZE];
CK_ULONG status_index = 0;
float status_last = 0.0;
float status_incr = 0.0;
int pos;
ssize_t nread;
boolean_t errflag = B_FALSE;
datalen = sizeof (databuf);
resultbuflen = sizeof (outbuf);
resultbuf = outbuf;
if (vflag && iflag)
status_incr = (insize / 79.0);
while ((nread = read(infd, databuf, datalen)) > 0) {
resultlen = resultbuflen;
rv = cmd->Update(hSession, databuf, (CK_ULONG)nread,
resultbuf, &resultlen);
if (rv == CKR_BUFFER_TOO_SMALL) {
if (resultbuf != NULL && resultbuf != outbuf) {
bzero(resultbuf, resultbuflen);
free(resultbuf);
}
if ((resultbuf = malloc((size_t)resultlen)) == NULL) {
int err = errno;
cryptoerror(LOG_STDERR, gettext("malloc: %s"),
strerror(err));
return (-1);
}
resultbuflen = resultlen;
rv = cmd->Update(hSession, databuf, (CK_ULONG)nread,
resultbuf, &resultlen);
}
if (rv != CKR_OK) {
errflag = B_TRUE;
cryptoerror(LOG_STDERR, gettext(
"crypto operation failed: %s"),
pkcs11_strerror(rv));
break;
}
if (write(outfd, resultbuf, resultlen) != resultlen) {
cryptoerror(LOG_STDERR, gettext(
"failed to write result to output file."));
errflag = B_TRUE;
break;
}
if (vflag) {
status_index += resultlen;
if (!iflag) {
if (status_pos == 0) {
(void) fprintf(stderr, gettext("."));
status_pos = 1;
}
while ((status_index - status_last) >
(PROGRESSSIZE)) {
(void) fprintf(stderr, gettext("."));
status_last += PROGRESSSIZE;
}
continue;
}
if (insize <= BUFFERSIZE)
pos = 78;
else
pos = (int)((status_index - status_last) /
status_incr);
if (pos > 0) {
print_status(pos);
status_last += (status_incr * pos);
}
}
}
if (vflag) {
if (iflag)
(void) fprintf(stderr, "]");
(void) fprintf(stderr, "\n%s\n", gettext("Done."));
}
if (nread == -1) {
cryptoerror(LOG_STDERR, gettext(
"error reading from input file"));
errflag = B_TRUE;
}
if (!errflag) {
rv = cmd->Final(hSession, resultbuf, &resultlen);
if (rv == CKR_OK) {
if (write(outfd, resultbuf, resultlen) != resultlen) {
cryptoerror(LOG_STDERR, gettext(
"failed to write result to output file."));
errflag = B_TRUE;
}
} else {
cryptoerror(LOG_STDERR, gettext(
"crypto operation failed: %s"),
pkcs11_strerror(rv));
errflag = B_TRUE;
}
}
if (resultbuf != NULL && resultbuf != outbuf) {
bzero(resultbuf, resultbuflen);
free(resultbuf);
}
if (errflag) {
return (-1);
} else {
return (0);
}
}