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 2009 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 int maxlen; 156 digest_buf_t *bufp; 157 boolean_t use_soft = B_FALSE; 158 crypto_active_op_t *opp; 159 160 if (opflag & OP_DIGEST) { 161 opp = &(session_p->digest); 162 if (!SLOT_HAS_LIMITED_HASH(session_p)) 163 return (CKR_ARGUMENTS_BAD); 164 maxlen = SLOT_HASH_MAX_INDATA_LEN(session_p); 165 } else if (opflag & (OP_SIGN | OP_VERIFY)) { 166 opp = (opflag & OP_SIGN) ? 167 &(session_p->sign) : &(session_p->verify); 168 if (!SLOT_HAS_LIMITED_HMAC(session_p)) 169 return (CKR_ARGUMENTS_BAD); 170 maxlen = SLOT_HMAC_MAX_INDATA_LEN(session_p); 171 } else 172 return (CKR_ARGUMENTS_BAD); 173 174 if (opp->flags & CRYPTO_EMULATE_USING_SW) { 175 opflag |= OP_UPDATE; 176 DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag); 177 opp->flags |= CRYPTO_EMULATE_UPDATE_DONE; 178 return (rv); 179 } 180 181 bufp = opp->context; 182 if (bufp == NULL) { 183 return (CKR_FUNCTION_FAILED); 184 } 185 186 /* Did we exceed the maximum allowed? */ 187 if (bufp->indata_len + ulPartLen > maxlen) { 188 use_soft = B_TRUE; 189 } else if (ulPartLen > (bufp->buf_len - bufp->indata_len)) { 190 int siz = ulPartLen < bufp->buf_len ? 191 bufp->buf_len * 2 : bufp->buf_len + ulPartLen; 192 uint8_t *old = bufp->buf; 193 194 bufp->buf = realloc(bufp->buf, siz); 195 if (bufp->buf == NULL) { 196 /* Try harder rather than failing */ 197 bufp->buf = old; 198 use_soft = B_TRUE; 199 } else 200 bufp->buf_len = siz; 201 } 202 203 if (use_soft) { 204 opp->flags |= CRYPTO_EMULATE_USING_SW; 205 206 if (opflag & OP_DIGEST) { 207 CK_MECHANISM_PTR pMechanism; 208 209 pMechanism = &(opp->mech); 210 rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0, 211 NULL, NULL, OP_INIT); 212 if (rv != CKR_OK) 213 return (rv); 214 } 215 216 opflag |= OP_UPDATE; 217 DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag); 218 opp->flags |= CRYPTO_EMULATE_UPDATE_DONE; 219 if (rv == CKR_OK) { 220 DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag); 221 } 222 223 return (rv); 224 } 225 226 /* accumulate the update data */ 227 bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen); 228 bufp->indata_len += ulPartLen; 229 230 return (CKR_OK); 231 } 232