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