2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <errno.h>
2N/A#include <stdio.h>
2N/A#include <strings.h>
2N/A#include <sys/crypto/ioctl.h>
2N/A#include <security/cryptoki.h>
2N/A#include "kernelGlobal.h"
2N/A#include "kernelSession.h"
2N/A#include "kernelEmulate.h"
2N/A
2N/A/*
2N/A * Helper routine to know if this is a HMAC. We can't just check
2N/A * the CKF_SIGN mech flag as it is set for non-HMAC mechs too.
2N/A */
2N/Aboolean_t
2N/Ais_hmac(CK_MECHANISM_TYPE mechanism)
2N/A{
2N/A switch (mechanism) {
2N/A case CKM_SSL3_MD5_MAC:
2N/A case CKM_SSL3_SHA1_MAC:
2N/A case CKM_MD5_HMAC_GENERAL:
2N/A case CKM_MD5_HMAC:
2N/A case CKM_SHA_1_HMAC_GENERAL:
2N/A case CKM_SHA_1_HMAC:
2N/A case CKM_SHA224_HMAC_GENERAL:
2N/A case CKM_SHA224_HMAC:
2N/A case CKM_SHA256_HMAC_GENERAL:
2N/A case CKM_SHA256_HMAC:
2N/A case CKM_SHA384_HMAC_GENERAL:
2N/A case CKM_SHA384_HMAC:
2N/A case CKM_SHA512_HMAC_GENERAL:
2N/A case CKM_SHA512_HMAC:
2N/A return (B_TRUE);
2N/A
2N/A default:
2N/A return (B_FALSE);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Helper routine to allocate an emulation structure for the session.
2N/A * buflen indicates the size of the scratch buffer to be allocated.
2N/A */
2N/ACK_RV
2N/Aemulate_buf_init(kernel_session_t *session_p, int buflen, int opflag)
2N/A{
2N/A digest_buf_t *bufp;
2N/A crypto_active_op_t *opp;
2N/A
2N/A opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \
2N/A ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify));
2N/A
2N/A bufp = opp->context;
2N/A
2N/A if (bufp != NULL) {
2N/A bufp->indata_len = 0;
2N/A /*
2N/A * We can reuse the context structure, digest_buf_t.
2N/A * See if we can reuse the scratch buffer in the context too.
2N/A */
2N/A if (buflen > bufp->buf_len) {
2N/A free(bufp->buf);
2N/A bufp->buf = NULL;
2N/A }
2N/A } else {
2N/A bufp = opp->context = calloc(1, sizeof (digest_buf_t));
2N/A if (bufp == NULL) {
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A }
2N/A
2N/A if (bufp->buf == NULL) {
2N/A bufp->buf = malloc(buflen);
2N/A if (bufp->buf == NULL) {
2N/A free(bufp);
2N/A opp->context = NULL;
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A bufp->buf_len = buflen;
2N/A }
2N/A
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A/*
2N/A * Setup the support necessary to do this operation in a
2N/A * single part. We allocate a buffer to accumulate the
2N/A * input data from later calls. We also get ready for
2N/A * the case where we have to do it in software by initializing
2N/A * a standby context. The opflag tells if this is a sign or verify.
2N/A */
2N/ACK_RV
2N/Aemulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism,
2N/A crypto_key_t *keyp, int opflag)
2N/A{
2N/A CK_RV rv;
2N/A crypto_active_op_t *opp;
2N/A
2N/A if ((rv = emulate_buf_init(session_p, EDIGEST_LENGTH, opflag)) !=
2N/A CKR_OK)
2N/A return (rv);
2N/A
2N/A opp = (opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify);
2N/A
2N/A opflag |= OP_INIT;
2N/A rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data,
2N/A keyp->ck_length >> 3, opflag);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A#define DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag) \
2N/A if ((opflag) & OP_DIGEST) { \
2N/A rv = do_soft_digest(get_spp(opp), NULL, pPart, \
2N/A ulPartLen, NULL, NULL, opflag); \
2N/A } else { \
2N/A rv = do_soft_hmac_update(get_spp(opp), pPart, \
2N/A ulPartLen, opflag); \
2N/A }
2N/A
2N/A/*
2N/A * Accumulate the input data in the buffer, allocating a bigger
2N/A * buffer if needed. If we reach the maximum input data size
2N/A * that can be accumulated, start using the software from then on.
2N/A * The opflag tells if this is a digest, sign or verify.
2N/A */
2N/ACK_RV
2N/Aemulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart,
2N/A CK_ULONG ulPartLen, int opflag)
2N/A{
2N/A CK_RV rv;
2N/A size_t maxlen;
2N/A digest_buf_t *bufp;
2N/A boolean_t use_soft = B_FALSE;
2N/A crypto_active_op_t *opp;
2N/A
2N/A if (opflag & OP_DIGEST) {
2N/A opp = &(session_p->digest);
2N/A maxlen = SLOT_HASH_MAX_INDATA_LEN(session_p);
2N/A } else if (opflag & (OP_SIGN | OP_VERIFY)) {
2N/A opp = (opflag & OP_SIGN) ?
2N/A &(session_p->sign) : &(session_p->verify);
2N/A if (!SLOT_HAS_LIMITED_HMAC(session_p))
2N/A return (CKR_ARGUMENTS_BAD);
2N/A maxlen = SLOT_HMAC_MAX_INDATA_LEN(session_p);
2N/A } else
2N/A return (CKR_ARGUMENTS_BAD);
2N/A
2N/A if (opp->flags & CRYPTO_EMULATE_USING_SW) {
2N/A opflag |= OP_UPDATE;
2N/A DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
2N/A opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
2N/A return (rv);
2N/A }
2N/A
2N/A bufp = opp->context;
2N/A if (bufp == NULL) {
2N/A return (CKR_FUNCTION_FAILED);
2N/A }
2N/A
2N/A /* Did we exceed the maximum allowed? */
2N/A if (bufp->indata_len + ulPartLen > maxlen) {
2N/A use_soft = B_TRUE;
2N/A } else if (ulPartLen > (bufp->buf_len - bufp->indata_len)) {
2N/A size_t siz = ulPartLen < bufp->buf_len ?
2N/A bufp->buf_len * 2 : bufp->buf_len + ulPartLen;
2N/A uint8_t *old = bufp->buf;
2N/A
2N/A bufp->buf = realloc(bufp->buf, siz);
2N/A if (bufp->buf == NULL) {
2N/A /* Try harder rather than failing */
2N/A bufp->buf = old;
2N/A use_soft = B_TRUE;
2N/A } else
2N/A bufp->buf_len = siz;
2N/A }
2N/A
2N/A if (use_soft) {
2N/A opp->flags |= CRYPTO_EMULATE_USING_SW;
2N/A
2N/A if (opflag & OP_DIGEST) {
2N/A CK_MECHANISM_PTR pMechanism;
2N/A
2N/A pMechanism = &(opp->mech);
2N/A rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0,
2N/A NULL, NULL, OP_INIT);
2N/A if (rv != CKR_OK)
2N/A return (rv);
2N/A }
2N/A
2N/A opflag |= OP_UPDATE;
2N/A DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag);
2N/A opp->flags |= CRYPTO_EMULATE_UPDATE_DONE;
2N/A if (rv == CKR_OK) {
2N/A DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag);
2N/A }
2N/A
2N/A return (rv);
2N/A }
2N/A
2N/A /* accumulate the update data */
2N/A bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen);
2N/A bufp->indata_len += ulPartLen;
2N/A
2N/A return (CKR_OK);
2N/A}