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 * Setup the support necessary to do this operation in a 67 * single part. We allocate a buffer to accumulate the 68 * input data from later calls. We also get ready for 69 * the case where we have to do it in software by initializing 70 * a standby context. The opflag tells if this is a digest, sign or verify. 71 */ 72 CK_RV 73 emulate_init(kernel_session_t *session_p, CK_MECHANISM_PTR pMechanism, 74 crypto_key_t *keyp, int opflag) 75 { 76 CK_RV rv; 77 digest_buf_t *bufp; 78 crypto_active_op_t *opp; 79 80 opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \ 81 ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify)); 82 83 bufp = opp->context; 84 if (bufp == NULL) { 85 bufp = calloc(1, sizeof (digest_buf_t)); 86 if (bufp == NULL) { 87 return (CKR_HOST_MEMORY); 88 } 89 90 bufp->buf = malloc(EDIGEST_LENGTH); 91 if (bufp->buf == NULL) { 92 free(bufp); 93 return (CKR_HOST_MEMORY); 94 } 95 bufp->buf_len = EDIGEST_LENGTH; 96 bufp->indata_len = 0; 97 opp->context = bufp; 98 } else 99 bufp->indata_len = 0; 100 101 opflag |= OP_INIT; 102 if (opflag & OP_DIGEST) { 103 rv = do_soft_digest(get_spp(opp), pMechanism, NULL, 0, 104 NULL, NULL, opflag); 105 } else { 106 rv = do_soft_hmac_init(get_spp(opp), pMechanism, keyp->ck_data, 107 keyp->ck_length >> 3, opflag); 108 } 109 110 return (rv); 111 } 112 113 #define DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag) \ 114 if ((opflag) & OP_DIGEST) { \ 115 rv = do_soft_digest(get_spp(opp), NULL, pPart, \ 116 ulPartLen, NULL, NULL, opflag); \ 117 } else { \ 118 rv = do_soft_hmac_update(get_spp(opp), pPart, \ 119 ulPartLen, opflag); \ 120 } 121 122 /* 123 * Accumulate the input data in the buffer, allocating a bigger 124 * buffer if needed. If we reach the maximum input data size 125 * that can be accumulated, start using the software from then on. 126 * The opflag tells if this is a digest, sign or verify. 127 */ 128 CK_RV 129 emulate_update(kernel_session_t *session_p, CK_BYTE_PTR pPart, 130 CK_ULONG ulPartLen, int opflag) 131 { 132 CK_RV rv; 133 digest_buf_t *bufp; 134 boolean_t use_soft = B_FALSE; 135 crypto_active_op_t *opp; 136 137 opp = (opflag & OP_DIGEST) ? &(session_p->digest) : \ 138 ((opflag & OP_SIGN) ? &(session_p->sign) : &(session_p->verify)); 139 140 if (!SLOT_HAS_LIMITED_HASH(session_p)) 141 return (CKR_ARGUMENTS_BAD); 142 143 if (opp->flags & CRYPTO_EMULATE_USING_SW) { 144 opflag |= OP_UPDATE; 145 DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag); 146 opp->flags |= CRYPTO_EMULATE_UPDATE_DONE; 147 return (rv); 148 } 149 150 bufp = opp->context; 151 if (bufp == NULL) { 152 return (CKR_FUNCTION_FAILED); 153 } 154 155 /* Did we exceed the maximum allowed? */ 156 if (bufp->indata_len + ulPartLen > SLOT_MAX_INDATA_LEN(session_p)) { 157 use_soft = B_TRUE; 158 } else if (ulPartLen > (bufp->buf_len - bufp->indata_len)) { 159 int siz = ulPartLen < bufp->buf_len ? 160 bufp->buf_len * 2 : bufp->buf_len + ulPartLen; 161 uint8_t *old = bufp->buf; 162 163 bufp->buf = realloc(bufp->buf, siz); 164 if (bufp->buf == NULL) { 165 /* Try harder rather than failing */ 166 bufp->buf = old; 167 use_soft = B_TRUE; 168 } else 169 bufp->buf_len = siz; 170 } 171 172 if (use_soft) { 173 opp->flags |= CRYPTO_EMULATE_USING_SW; 174 175 opflag |= OP_UPDATE; 176 DO_SOFT_UPDATE(opp, bufp->buf, bufp->indata_len, opflag); 177 opp->flags |= CRYPTO_EMULATE_UPDATE_DONE; 178 if (rv == CKR_OK) { 179 DO_SOFT_UPDATE(opp, pPart, ulPartLen, opflag); 180 } 181 182 return (rv); 183 } 184 185 /* accumulate the update data */ 186 bcopy(pPart, bufp->buf + bufp->indata_len, ulPartLen); 187 bufp->indata_len += ulPartLen; 188 189 return (CKR_OK); 190 } 191