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