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 <pthread.h> 30 #include <errno.h> 31 #include <stdio.h> 32 #include <strings.h> 33 #include <sys/crypto/ioctl.h> 34 #include <security/cryptoki.h> 35 #include <security/pkcs11t.h> 36 #include "softSession.h" 37 #include "softObject.h" 38 #include "softOps.h" 39 #include "softMAC.h" 40 #include "kernelSoftCommon.h" 41 42 /* 43 * Do the operation(s) specified by opflag. 44 */ 45 CK_RV 46 do_soft_digest(void **s, CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pData, 47 CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen, 48 int opflag) 49 { 50 soft_session_t *session_p; 51 CK_RV rv = CKR_ARGUMENTS_BAD; 52 53 session_p = *((soft_session_t **)s); 54 if (session_p == NULL) { 55 if (!(opflag & OP_INIT)) { 56 return (CKR_ARGUMENTS_BAD); 57 } 58 59 session_p = calloc(1, sizeof (soft_session_t)); 60 /* 61 * Initialize the lock for the newly created session. 62 * We do only the minimum needed setup for the 63 * soft_digest* routines to succeed. 64 */ 65 if (pthread_mutex_init(&session_p->session_mutex, NULL) != 0) { 66 free(session_p); 67 return (CKR_CANT_LOCK); 68 } 69 70 *s = session_p; 71 } else if (opflag & OP_INIT) { 72 free_soft_ctx(session_p, OP_DIGEST); 73 } 74 75 if (opflag & OP_INIT) { 76 rv = soft_digest_init(session_p, pMechanism); 77 if (rv != CKR_OK) 78 return (rv); 79 } 80 81 if (opflag & OP_SINGLE) { 82 rv = soft_digest(session_p, pData, ulDataLen, 83 pDigest, pulDigestLen); 84 } else { 85 if (opflag & OP_UPDATE) { 86 rv = soft_digest_update(session_p, pData, ulDataLen); 87 if (rv != CKR_OK) 88 return (rv); 89 } 90 91 if (opflag & OP_FINAL) { 92 rv = soft_digest_final(session_p, 93 pDigest, pulDigestLen); 94 } 95 } 96 97 return (rv); 98 } 99 100 /* 101 * opflag specifies whether this is a sign or verify. 102 */ 103 CK_RV 104 do_soft_hmac_init(void **s, CK_MECHANISM_PTR pMechanism, 105 CK_BYTE_PTR kval, CK_ULONG klen, int opflag) 106 { 107 CK_RV rv; 108 soft_object_t keyobj; 109 secret_key_obj_t skeyobj; 110 soft_object_t *key_p; 111 soft_session_t *session_p; 112 113 session_p = *((soft_session_t **)s); 114 if (session_p == NULL) { 115 session_p = calloc(1, sizeof (soft_session_t)); 116 /* See comments in do_soft_digest() above */ 117 if (pthread_mutex_init(&session_p->session_mutex, NULL) != 0) { 118 free(session_p); 119 return (CKR_CANT_LOCK); 120 } 121 122 *s = session_p; 123 } else if (opflag & OP_INIT) { 124 free_soft_ctx(session_p, opflag); 125 } 126 127 /* Do the minimum needed setup for the call to succeed */ 128 key_p = &keyobj; 129 bzero(key_p, sizeof (soft_object_t)); 130 key_p->class = CKO_SECRET_KEY; 131 key_p->key_type = CKK_GENERIC_SECRET; 132 133 bzero(&skeyobj, sizeof (secret_key_obj_t)); 134 OBJ_SEC(key_p) = &skeyobj; 135 OBJ_SEC_VALUE(key_p) = kval; 136 OBJ_SEC_VALUE_LEN(key_p) = klen; 137 138 rv = soft_hmac_sign_verify_init_common(session_p, pMechanism, 139 key_p, opflag & OP_SIGN); 140 141 return (rv); 142 } 143 144 /* 145 * opflag specifies whether this is a sign or verify. 146 */ 147 CK_RV 148 do_soft_hmac_update(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen, int opflag) 149 { 150 soft_session_t *session_p; 151 152 session_p = *((soft_session_t **)s); 153 if (session_p == NULL) { 154 return (CKR_ARGUMENTS_BAD); 155 } 156 157 return (soft_hmac_sign_verify_update(session_p, 158 pData, ulDataLen, opflag & OP_SIGN)); 159 } 160 161 /* 162 * opflag specifies whether this is a final or single. 163 */ 164 CK_RV 165 do_soft_hmac_sign(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 166 CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen, int opflag) 167 { 168 CK_RV rv; 169 soft_session_t *session_p; 170 CK_BYTE hmac[SHA512_DIGEST_LENGTH]; /* use the maximum size */ 171 172 session_p = *((soft_session_t **)s); 173 if (session_p == NULL || !(opflag & OP_SINGLE || opflag & OP_FINAL)) { 174 return (CKR_ARGUMENTS_BAD); 175 } 176 177 rv = soft_hmac_sign_verify_common(session_p, pData, ulDataLen, 178 (pSignature != NULL ? hmac : NULL), pulSignatureLen, B_TRUE); 179 180 if ((rv == CKR_OK) && (pSignature != NULL)) { 181 (void) memcpy(pSignature, hmac, *pulSignatureLen); 182 } 183 184 return (rv); 185 } 186 187 /* 188 * opflag specifies whether this is a final or single. 189 */ 190 CK_RV 191 do_soft_hmac_verify(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 192 CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, int opflag) 193 { 194 CK_RV rv; 195 CK_ULONG len; 196 soft_session_t *session_p; 197 soft_hmac_ctx_t *hmac_ctx; 198 CK_BYTE hmac[SHA512_DIGEST_LENGTH]; /* use the maximum size */ 199 200 session_p = *((soft_session_t **)s); 201 if (session_p == NULL || !(opflag & OP_SINGLE || opflag & OP_FINAL)) { 202 return (CKR_ARGUMENTS_BAD); 203 } 204 205 hmac_ctx = (soft_hmac_ctx_t *)session_p->verify.context; 206 len = hmac_ctx->hmac_len; 207 208 rv = soft_hmac_sign_verify_common(session_p, pData, 209 ulDataLen, hmac, &len, B_FALSE); 210 211 if (rv == CKR_OK) { 212 if (len != ulSignatureLen) { 213 rv = CKR_SIGNATURE_LEN_RANGE; 214 } 215 216 if (memcmp(hmac, pSignature, len) != 0) { 217 rv = CKR_SIGNATURE_INVALID; 218 } 219 } 220 221 return (rv); 222 } 223 224 /* 225 * Helper routine to handle the case when the ctx is abandoned. 226 */ 227 void 228 free_soft_ctx(void *s, int opflag) 229 { 230 soft_session_t *session_p; 231 232 session_p = (soft_session_t *)s; 233 if (session_p == NULL) 234 return; 235 236 if (opflag & OP_SIGN) { 237 if (session_p->sign.context == NULL) 238 return; 239 bzero(session_p->sign.context, sizeof (soft_hmac_ctx_t)); 240 free(session_p->sign.context); 241 session_p->sign.context = NULL; 242 session_p->sign.flags = 0; 243 } else if (opflag & OP_VERIFY) { 244 if (session_p->verify.context == NULL) 245 return; 246 bzero(session_p->verify.context, sizeof (soft_hmac_ctx_t)); 247 free(session_p->verify.context); 248 session_p->verify.context = NULL; 249 session_p->verify.flags = 0; 250 } else { 251 if (session_p->digest.context == NULL) 252 return; 253 free(session_p->digest.context); 254 session_p->digest.context = NULL; 255 session_p->digest.flags = 0; 256 } 257 } 258