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