#include <errno.h>
#include <stdio.h>
#include <strings.h>
#include <sys/crypto/ioctl.h>
#include <security/cryptoki.h>
#include "kernelGlobal.h"
#include "kernelSession.h"
#include "kernelEmulate.h"
boolean_t
is_hmac(CK_MECHANISM_TYPE mechanism)
{
switch (mechanism) {
case CKM_SSL3_MD5_MAC:
case CKM_SSL3_SHA1_MAC:
case CKM_MD5_HMAC_GENERAL:
case CKM_MD5_HMAC:
case CKM_SHA_1_HMAC_GENERAL:
case CKM_SHA_1_HMAC:
case CKM_SHA256_HMAC_GENERAL:
case CKM_SHA256_HMAC:
case CKM_SHA384_HMAC_GENERAL:
case CKM_SHA384_HMAC:
case CKM_SHA512_HMAC_GENERAL:
case CKM_SHA512_HMAC:
return (B_TRUE);
default:
return (B_FALSE);
}
}
CK_RV
emulate_buf_init(kernel_session_t *session_p, int buflen, int opflag)
{
digest_buf_t *bufp;
crypto_active_op_t *opp;
opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \
((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify));
bufp = opp->context;
if (bufp != NULL) {
bufp->indata_len = 0;
if (buflen > bufp->buf_len) {
free(bufp->buf);
bufp->buf = NULL;
}
} else {
bufp = opp->context = calloc(1, sizeof (digest_buf_t));
if (bufp == NULL) {
return (CKR_HOST_MEMORY);
}
}
if (bufp->buf == NULL) {
bufp->buf = malloc(buflen);
if (bufp->buf == NULL) {
free(bufp);
opp->context = NULL;
return (CKR_HOST_MEMORY);
}
bufp->buf_len = buflen;
}
return (CKR_OK);
}
CK_RV
emulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism,
crypto_key_t *keyp, int opflag)
{
CK_RV rv;
crypto_active_op_t *opp;
if ((rv = emulate_buf_init(session_p, EDIGEST_LENGTH, opflag)) !=
CKR_OK)
return (rv);
opp = (opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify);
opflag |= OP_INIT;
rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data,
keyp->ck_length >> 3, opflag);
return (rv);
}
#define DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag) \
if ((opflag) & OP_DIGEST) { \
rv = do_soft_digest(get_spp(opp), NULL, pPart, \
ulPartLen, NULL, NULL, opflag); \
} else { \
rv = do_soft_hmac_update(get_spp(opp), pPart, \
ulPartLen, opflag); \
}
CK_RV
emulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart,
CK_ULONG ulPartLen, int opflag)
{
CK_RV rv;
int maxlen;
digest_buf_t *bufp;
boolean_t use_soft = B_FALSE;
crypto_active_op_t *opp;
if (opflag & OP_DIGEST) {
opp = &(session_p->digest);
if (!SLOT_HAS_LIMITED_HASH(session_p))
return (CKR_ARGUMENTS_BAD);
maxlen = SLOT_HASH_MAX_INDATA_LEN(session_p);
} else if (opflag & (OP_SIGN | OP_VERIFY)) {
opp = (opflag & OP_SIGN) ?
&(session_p->sign) : &(session_p->verify);
if (!SLOT_HAS_LIMITED_HMAC(session_p))
return (CKR_ARGUMENTS_BAD);
maxlen = SLOT_HMAC_MAX_INDATA_LEN(session_p);
} else
return (CKR_ARGUMENTS_BAD);
if (opp->flags & CRYPTO_EMULATE_USING_SW) {
opflag |= OP_UPDATE;
DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
return (rv);
}
bufp = opp->context;
if (bufp == NULL) {
return (CKR_FUNCTION_FAILED);
}
if (bufp->indata_len + ulPartLen > maxlen) {
use_soft = B_TRUE;
} else if (ulPartLen > (bufp->buf_len - bufp->indata_len)) {
int siz = ulPartLen < bufp->buf_len ?
bufp->buf_len * 2 : bufp->buf_len + ulPartLen;
uint8_t *old = bufp->buf;
bufp->buf = realloc(bufp->buf, siz);
if (bufp->buf == NULL) {
bufp->buf = old;
use_soft = B_TRUE;
} else
bufp->buf_len = siz;
}
if (use_soft) {
opp->flags |= CRYPTO_EMULATE_USING_SW;
if (opflag & OP_DIGEST) {
CK_MECHANISM_PTR pMechanism;
pMechanism = &(opp->mech);
rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0,
NULL, NULL, OP_INIT);
if (rv != CKR_OK)
return (rv);
}
opflag |= OP_UPDATE;
DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag);
opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
if (rv == CKR_OK) {
DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
}
return (rv);
}
bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen);
bufp->indata_len += ulPartLen;
return (CKR_OK);
}