1ba5f469cSkrishna /* 2ba5f469cSkrishna * CDDL HEADER START 3ba5f469cSkrishna * 4ba5f469cSkrishna * The contents of this file are subject to the terms of the 5ba5f469cSkrishna * Common Development and Distribution License (the "License"). 6ba5f469cSkrishna * You may not use this file except in compliance with the License. 7ba5f469cSkrishna * 8ba5f469cSkrishna * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ba5f469cSkrishna * or http://www.opensolaris.org/os/licensing. 10ba5f469cSkrishna * See the License for the specific language governing permissions 11ba5f469cSkrishna * and limitations under the License. 12ba5f469cSkrishna * 13ba5f469cSkrishna * When distributing Covered Code, include this CDDL HEADER in each 14ba5f469cSkrishna * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ba5f469cSkrishna * If applicable, add the following below this CDDL HEADER, with the 16ba5f469cSkrishna * fields enclosed by brackets "[]" replaced with your own identifying 17ba5f469cSkrishna * information: Portions Copyright [yyyy] [name of copyright owner] 18ba5f469cSkrishna * 19ba5f469cSkrishna * CDDL HEADER END 20ba5f469cSkrishna */ 21ba5f469cSkrishna 22ba5f469cSkrishna /* 23*4df55fdeSJanie Lu * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24ba5f469cSkrishna * Use is subject to license terms. 25ba5f469cSkrishna */ 26ba5f469cSkrishna 27ba5f469cSkrishna #include <errno.h> 28ba5f469cSkrishna #include <stdio.h> 29ba5f469cSkrishna #include <strings.h> 30ba5f469cSkrishna #include <sys/crypto/ioctl.h> 31ba5f469cSkrishna #include <security/cryptoki.h> 32ba5f469cSkrishna #include "kernelGlobal.h" 33ba5f469cSkrishna #include "kernelSession.h" 34ba5f469cSkrishna #include "kernelEmulate.h" 35ba5f469cSkrishna 36ba5f469cSkrishna /* 37ba5f469cSkrishna * Helper routine to know if this is a HMAC. We can't just check 38ba5f469cSkrishna * the CKF_SIGN mech flag as it is set for non-HMAC mechs too. 39ba5f469cSkrishna */ 40ba5f469cSkrishna boolean_t 41ba5f469cSkrishna is_hmac(CK_MECHANISM_TYPE mechanism) 42ba5f469cSkrishna { 43ba5f469cSkrishna switch (mechanism) { 44ba5f469cSkrishna case CKM_SSL3_MD5_MAC: 45ba5f469cSkrishna case CKM_SSL3_SHA1_MAC: 46ba5f469cSkrishna case CKM_MD5_HMAC_GENERAL: 47ba5f469cSkrishna case CKM_MD5_HMAC: 48ba5f469cSkrishna case CKM_SHA_1_HMAC_GENERAL: 49ba5f469cSkrishna case CKM_SHA_1_HMAC: 50ba5f469cSkrishna case CKM_SHA256_HMAC_GENERAL: 51ba5f469cSkrishna case CKM_SHA256_HMAC: 52ba5f469cSkrishna case CKM_SHA384_HMAC_GENERAL: 53ba5f469cSkrishna case CKM_SHA384_HMAC: 54ba5f469cSkrishna case CKM_SHA512_HMAC_GENERAL: 55ba5f469cSkrishna case CKM_SHA512_HMAC: 56ba5f469cSkrishna return (B_TRUE); 57ba5f469cSkrishna 58ba5f469cSkrishna default: 59ba5f469cSkrishna return (B_FALSE); 60ba5f469cSkrishna } 61ba5f469cSkrishna } 62ba5f469cSkrishna 63ba5f469cSkrishna /* 64b2a96221Skrishna * Helper routine to allocate an emulation structure for the session. 65b2a96221Skrishna * buflen indicates the size of the scratch buffer to be allocated. 66ba5f469cSkrishna */ 67ba5f469cSkrishna CK_RV 68b2a96221Skrishna emulate_buf_init(kernel_session_t *session_p, int buflen, int opflag) 69ba5f469cSkrishna { 70ba5f469cSkrishna digest_buf_t *bufp; 71ba5f469cSkrishna crypto_active_op_t *opp; 72ba5f469cSkrishna 73ba5f469cSkrishna opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \ 74ba5f469cSkrishna ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify)); 75ba5f469cSkrishna 76ba5f469cSkrishna bufp = opp->context; 77b2a96221Skrishna 78b2a96221Skrishna if (bufp != NULL) { 79b2a96221Skrishna bufp->indata_len = 0; 800d94eea1SKrishna Yenduri /* 810d94eea1SKrishna Yenduri * We can reuse the context structure, digest_buf_t. 820d94eea1SKrishna Yenduri * See if we can reuse the scratch buffer in the context too. 830d94eea1SKrishna Yenduri */ 84b2a96221Skrishna if (buflen > bufp->buf_len) { 850d94eea1SKrishna Yenduri free(bufp->buf); 860d94eea1SKrishna Yenduri bufp->buf = NULL; 87b2a96221Skrishna } 880d94eea1SKrishna Yenduri } else { 890d94eea1SKrishna Yenduri bufp = opp->context = calloc(1, sizeof (digest_buf_t)); 90ba5f469cSkrishna if (bufp == NULL) { 91ba5f469cSkrishna return (CKR_HOST_MEMORY); 92ba5f469cSkrishna } 930d94eea1SKrishna Yenduri } 94ba5f469cSkrishna 950d94eea1SKrishna Yenduri if (bufp->buf == NULL) { 96b2a96221Skrishna bufp->buf = malloc(buflen); 97ba5f469cSkrishna if (bufp->buf == NULL) { 98ba5f469cSkrishna free(bufp); 990d94eea1SKrishna Yenduri opp->context = NULL; 100ba5f469cSkrishna return (CKR_HOST_MEMORY); 101ba5f469cSkrishna } 102b2a96221Skrishna bufp->buf_len = buflen; 103b2a96221Skrishna } 104b2a96221Skrishna 105b2a96221Skrishna return (CKR_OK); 106b2a96221Skrishna } 107b2a96221Skrishna 108b2a96221Skrishna /* 109b2a96221Skrishna * Setup the support necessary to do this operation in a 110b2a96221Skrishna * single part. We allocate a buffer to accumulate the 111b2a96221Skrishna * input data from later calls. We also get ready for 112b2a96221Skrishna * the case where we have to do it in software by initializing 113b2a96221Skrishna * a standby context. The opflag tells if this is a sign or verify. 114b2a96221Skrishna */ 115b2a96221Skrishna CK_RV 116b2a96221Skrishna emulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism, 117b2a96221Skrishna crypto_key_t *keyp, int opflag) 118b2a96221Skrishna { 119b2a96221Skrishna CK_RV rv; 120b2a96221Skrishna crypto_active_op_t *opp; 121b2a96221Skrishna 122b2a96221Skrishna if ((rv = emulate_buf_init(session_p, EDIGEST_LENGTH, opflag)) != 123b2a96221Skrishna CKR_OK) 124b2a96221Skrishna return (rv); 125b2a96221Skrishna 126b2a96221Skrishna opp = (opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify); 127ba5f469cSkrishna 128ba5f469cSkrishna opflag |= OP_INIT; 129ba5f469cSkrishna rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data, 130ba5f469cSkrishna keyp->ck_length >> 3, opflag); 131ba5f469cSkrishna 132ba5f469cSkrishna return (rv); 133ba5f469cSkrishna } 134ba5f469cSkrishna 135ba5f469cSkrishna #define DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag) \ 136ba5f469cSkrishna if ((opflag) & OP_DIGEST) { \ 137ba5f469cSkrishna rv = do_soft_digest(get_spp(opp), NULL, pPart, \ 138ba5f469cSkrishna ulPartLen, NULL, NULL, opflag); \ 139ba5f469cSkrishna } else { \ 140ba5f469cSkrishna rv = do_soft_hmac_update(get_spp(opp), pPart, \ 141ba5f469cSkrishna ulPartLen, opflag); \ 142ba5f469cSkrishna } 143ba5f469cSkrishna 144ba5f469cSkrishna /* 145ba5f469cSkrishna * Accumulate the input data in the buffer, allocating a bigger 146ba5f469cSkrishna * buffer if needed. If we reach the maximum input data size 147ba5f469cSkrishna * that can be accumulated, start using the software from then on. 148ba5f469cSkrishna * The opflag tells if this is a digest, sign or verify. 149ba5f469cSkrishna */ 150ba5f469cSkrishna CK_RV 151ba5f469cSkrishna emulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart, 152ba5f469cSkrishna CK_ULONG ulPartLen, int opflag) 153ba5f469cSkrishna { 154ba5f469cSkrishna CK_RV rv; 155*4df55fdeSJanie Lu int maxlen; 156ba5f469cSkrishna digest_buf_t *bufp; 157ba5f469cSkrishna boolean_t use_soft = B_FALSE; 158ba5f469cSkrishna crypto_active_op_t *opp; 159ba5f469cSkrishna 160*4df55fdeSJanie Lu if (opflag & OP_DIGEST) { 161*4df55fdeSJanie Lu opp = &(session_p->digest); 162ba5f469cSkrishna if (!SLOT_HAS_LIMITED_HASH(session_p)) 163ba5f469cSkrishna return (CKR_ARGUMENTS_BAD); 164*4df55fdeSJanie Lu maxlen = SLOT_HASH_MAX_INDATA_LEN(session_p); 165*4df55fdeSJanie Lu } else if (opflag & (OP_SIGN | OP_VERIFY)) { 166*4df55fdeSJanie Lu opp = (opflag & OP_SIGN) ? 167*4df55fdeSJanie Lu &(session_p->sign) : &(session_p->verify); 168*4df55fdeSJanie Lu if (!SLOT_HAS_LIMITED_HMAC(session_p)) 169*4df55fdeSJanie Lu return (CKR_ARGUMENTS_BAD); 170*4df55fdeSJanie Lu maxlen = SLOT_HMAC_MAX_INDATA_LEN(session_p); 171*4df55fdeSJanie Lu } else 172*4df55fdeSJanie Lu return (CKR_ARGUMENTS_BAD); 173ba5f469cSkrishna 174ba5f469cSkrishna if (opp->flags & CRYPTO_EMULATE_USING_SW) { 175ba5f469cSkrishna opflag |= OP_UPDATE; 176ba5f469cSkrishna DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag); 177ba5f469cSkrishna opp->flags |= CRYPTO_EMULATE_UPDATE_DONE; 178ba5f469cSkrishna return (rv); 179ba5f469cSkrishna } 180ba5f469cSkrishna 181ba5f469cSkrishna bufp = opp->context; 182ba5f469cSkrishna if (bufp == NULL) { 183ba5f469cSkrishna return (CKR_FUNCTION_FAILED); 184ba5f469cSkrishna } 185ba5f469cSkrishna 186ba5f469cSkrishna /* Did we exceed the maximum allowed? */ 187*4df55fdeSJanie Lu if (bufp->indata_len + ulPartLen > maxlen) { 188ba5f469cSkrishna use_soft = B_TRUE; 189ba5f469cSkrishna } else if (ulPartLen > (bufp->buf_len - bufp->indata_len)) { 190ba5f469cSkrishna int siz = ulPartLen < bufp->buf_len ? 191ba5f469cSkrishna bufp->buf_len * 2 : bufp->buf_len + ulPartLen; 192ba5f469cSkrishna uint8_t *old = bufp->buf; 193ba5f469cSkrishna 194ba5f469cSkrishna bufp->buf = realloc(bufp->buf, siz); 195ba5f469cSkrishna if (bufp->buf == NULL) { 196ba5f469cSkrishna /* Try harder rather than failing */ 197ba5f469cSkrishna bufp->buf = old; 198ba5f469cSkrishna use_soft = B_TRUE; 199ba5f469cSkrishna } else 200ba5f469cSkrishna bufp->buf_len = siz; 201ba5f469cSkrishna } 202ba5f469cSkrishna 203ba5f469cSkrishna if (use_soft) { 204ba5f469cSkrishna opp->flags |= CRYPTO_EMULATE_USING_SW; 205ba5f469cSkrishna 206b2a96221Skrishna if (opflag & OP_DIGEST) { 207b2a96221Skrishna CK_MECHANISM_PTR pMechanism; 208b2a96221Skrishna 209b2a96221Skrishna pMechanism = &(opp->mech); 210b2a96221Skrishna rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0, 211b2a96221Skrishna NULL, NULL, OP_INIT); 212b2a96221Skrishna if (rv != CKR_OK) 213b2a96221Skrishna return (rv); 214b2a96221Skrishna } 215b2a96221Skrishna 216ba5f469cSkrishna opflag |= OP_UPDATE; 217ba5f469cSkrishna DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag); 218ba5f469cSkrishna opp->flags |= CRYPTO_EMULATE_UPDATE_DONE; 219ba5f469cSkrishna if (rv == CKR_OK) { 220ba5f469cSkrishna DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag); 221ba5f469cSkrishna } 222ba5f469cSkrishna 223ba5f469cSkrishna return (rv); 224ba5f469cSkrishna } 225ba5f469cSkrishna 226ba5f469cSkrishna /* accumulate the update data */ 227ba5f469cSkrishna bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen); 228ba5f469cSkrishna bufp->indata_len += ulPartLen; 229ba5f469cSkrishna 230ba5f469cSkrishna return (CKR_OK); 231ba5f469cSkrishna } 232