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