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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 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 <strings.h> 30 #include <md5.h> 31 #include <pthread.h> 32 #include <stdlib.h> 33 #include <sys/sha1.h> 34 #include <sys/types.h> 35 #include <security/cryptoki.h> 36 #include "softGlobal.h" 37 #include "softOps.h" 38 #include "softSession.h" 39 #include "softObject.h" 40 41 42 /* 43 * soft_digest_init() 44 * 45 * Arguments: 46 * session_p: pointer to soft_session_t struct 47 * pMechanism: pointer to CK_MECHANISM struct provided by application 48 * 49 * Description: 50 * called by C_DigestInit(). This function allocates space for 51 * context, then calls the corresponding software provided digest 52 * init routine based on the mechanism. 53 * 54 * Returns: 55 * CKR_OK: success 56 * CKR_HOST_MEMORY: run out of system memory 57 * CKR_MECHANISM_INVALID: invalid mechanism type 58 */ 59 CK_RV 60 soft_digest_init(soft_session_t *session_p, CK_MECHANISM_PTR pMechanism) 61 { 62 63 switch (pMechanism->mechanism) { 64 65 case CKM_MD5: 66 (void) pthread_mutex_lock(&session_p->session_mutex); 67 68 session_p->digest.context = malloc(sizeof (MD5_CTX)); 69 70 if (session_p->digest.context == NULL) { 71 (void) pthread_mutex_unlock(&session_p->session_mutex); 72 return (CKR_HOST_MEMORY); 73 } 74 75 session_p->digest.mech.mechanism = CKM_MD5; 76 (void) pthread_mutex_unlock(&session_p->session_mutex); 77 78 MD5Init((MD5_CTX *)session_p->digest.context); 79 80 break; 81 82 case CKM_SHA_1: 83 84 (void) pthread_mutex_lock(&session_p->session_mutex); 85 86 session_p->digest.context = malloc(sizeof (SHA1_CTX)); 87 88 if (session_p->digest.context == NULL) { 89 (void) pthread_mutex_unlock(&session_p->session_mutex); 90 return (CKR_HOST_MEMORY); 91 } 92 93 session_p->digest.mech.mechanism = CKM_SHA_1; 94 (void) pthread_mutex_unlock(&session_p->session_mutex); 95 96 SHA1Init((SHA1_CTX *)session_p->digest.context); 97 98 break; 99 100 default: 101 return (CKR_MECHANISM_INVALID); 102 } 103 104 return (CKR_OK); 105 } 106 107 108 /* 109 * soft_digest_common() 110 * 111 * Arguments: 112 * session_p: pointer to soft_session_t struct 113 * pData: pointer to the input data to be digested 114 * ulDataLen: length of the input data 115 * pDigest: pointer to the output data after digesting 116 * pulDigestLen: length of the output data 117 * 118 * Description: 119 * called by soft_digest() or soft_digest_final(). This function 120 * determines the length of output buffer and calls the corresponding 121 * software provided digest routine based on the mechanism. 122 * 123 * Returns: 124 * CKR_OK: success 125 * CKR_MECHANISM_INVALID: invalid mechanism type 126 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application 127 * is too small 128 */ 129 CK_RV 130 soft_digest_common(soft_session_t *session_p, CK_BYTE_PTR pData, 131 CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) 132 { 133 134 CK_ULONG digestLen = 0; 135 size_t len = 0; 136 137 /* 138 * Determine the output data length based on the mechanism 139 */ 140 switch (session_p->digest.mech.mechanism) { 141 142 case CKM_MD5: 143 digestLen = 16; 144 break; 145 146 case CKM_SHA_1: 147 digestLen = 20; 148 break; 149 150 default: 151 return (CKR_MECHANISM_INVALID); 152 } 153 154 if (pDigest == NULL) { 155 /* 156 * Application only wants to know the length of the 157 * buffer needed to hold the message digest. 158 */ 159 *pulDigestLen = digestLen; 160 return (CKR_OK); 161 } 162 163 if (*pulDigestLen < digestLen) { 164 /* 165 * Application provides buffer too small to hold the 166 * digest message. Return the length of buffer needed 167 * to the application. 168 */ 169 *pulDigestLen = digestLen; 170 return (CKR_BUFFER_TOO_SMALL); 171 } 172 173 /* 174 * Call the corresponding system provided software digest routine. 175 * If the soft_digest_common() is called by soft_digest_final() 176 * the pData is NULL, and the ulDataLen is zero. 177 */ 178 switch (session_p->digest.mech.mechanism) { 179 180 case CKM_MD5: 181 if (pData != NULL) { 182 /* 183 * this is called by soft_digest() 184 */ 185 #ifdef __sparcv9 186 MD5Update((MD5_CTX *)session_p->digest.context, 187 /* LINTED */ 188 pData, (uint_t)ulDataLen); 189 #else /* !__sparcv9 */ 190 MD5Update((MD5_CTX *)session_p->digest.context, 191 pData, ulDataLen); 192 #endif /* __sparcv9 */ 193 MD5Final(pDigest, (MD5_CTX *)session_p->digest.context); 194 } else { 195 /* 196 * this is called by soft_digest_final() 197 */ 198 MD5Final(pDigest, (MD5_CTX *)session_p->digest.context); 199 len = sizeof (MD5_CTX); 200 } 201 break; 202 203 case CKM_SHA_1: 204 if (pData != NULL) { 205 /* 206 * this is called by soft_digest() 207 */ 208 209 #ifdef __sparcv9 210 SHA1Update((SHA1_CTX *)session_p->digest.context, 211 /* LINTED */ 212 pData, (uint32_t)ulDataLen); 213 #else /* !__sparcv9 */ 214 SHA1Update((SHA1_CTX *)session_p->digest.context, 215 pData, ulDataLen); 216 #endif /* __sparcv9 */ 217 SHA1Final(pDigest, 218 (SHA1_CTX *)session_p->digest.context); 219 } else { 220 /* 221 * this is called by soft_digest_final() 222 */ 223 SHA1Final(pDigest, 224 (SHA1_CTX *)session_p->digest.context); 225 len = sizeof (SHA1_CTX); 226 } 227 break; 228 } 229 230 /* Paranoia on behalf of C_DigestKey callers: bzero the context */ 231 if (session_p->digest.flags & CRYPTO_KEY_DIGESTED) { 232 bzero(session_p->digest.context, len); 233 session_p->digest.flags &= ~CRYPTO_KEY_DIGESTED; 234 } 235 *pulDigestLen = digestLen; 236 (void) pthread_mutex_lock(&session_p->session_mutex); 237 free(session_p->digest.context); 238 session_p->digest.context = NULL; 239 (void) pthread_mutex_unlock(&session_p->session_mutex); 240 241 return (CKR_OK); 242 } 243 244 245 /* 246 * soft_digest() 247 * 248 * Arguments: 249 * session_p: pointer to soft_session_t struct 250 * pData: pointer to the input data to be digested 251 * ulDataLen: length of the input data 252 * pDigest: pointer to the output data after digesting 253 * pulDigestLen: length of the output data 254 * 255 * Description: 256 * called by C_Digest(). This function calls soft_digest_common(). 257 * 258 * Returns: 259 * see return values in soft_digest_common(). 260 */ 261 CK_RV 262 soft_digest(soft_session_t *session_p, CK_BYTE_PTR pData, CK_ULONG ulDataLen, 263 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) 264 { 265 266 return (soft_digest_common(session_p, pData, ulDataLen, 267 pDigest, pulDigestLen)); 268 } 269 270 271 /* 272 * soft_digest_update() 273 * 274 * Arguments: 275 * session_p: pointer to soft_session_t struct 276 * pPart: pointer to the input data to be digested 277 * ulPartLen: length of the input data 278 * 279 * Description: 280 * called by C_DigestUpdate(). This function calls the corresponding 281 * software provided digest update routine based on the mechanism. 282 * 283 * Returns: 284 * CKR_OK: success 285 * CKR_MECHANISM_INVALID: invalid MECHANISM type. 286 */ 287 CK_RV 288 soft_digest_update(soft_session_t *session_p, CK_BYTE_PTR pPart, 289 CK_ULONG ulPartLen) 290 { 291 292 switch (session_p->digest.mech.mechanism) { 293 294 case CKM_MD5: 295 #ifdef __sparcv9 296 MD5Update((MD5_CTX *)session_p->digest.context, 297 /* LINTED */ 298 pPart, (uint_t)ulPartLen); 299 #else /* !__sparcv9 */ 300 MD5Update((MD5_CTX *)session_p->digest.context, 301 pPart, ulPartLen); 302 #endif /* __sparcv9 */ 303 break; 304 305 case CKM_SHA_1: 306 #ifdef __sparcv9 307 SHA1Update((SHA1_CTX *)session_p->digest.context, 308 /* LINTED */ 309 pPart, (uint32_t)ulPartLen); 310 #else /* !__sparcv9 */ 311 SHA1Update((SHA1_CTX *)session_p->digest.context, 312 pPart, ulPartLen); 313 #endif /* __sparcv9 */ 314 break; 315 316 default: 317 return (CKR_MECHANISM_INVALID); 318 } 319 320 return (CKR_OK); 321 } 322 323 324 /* 325 * soft_digest_final() 326 * 327 * Arguments: 328 * session_p: pointer to soft_session_t struct 329 * pDigest: pointer to the output data after digesting 330 * pulDigestLen: length of the output data 331 * 332 * Description: 333 * called by C_DigestFinal(). This function calls soft_digest_common(). 334 * 335 * Returns: 336 * see return values in soft_digest_common(). 337 */ 338 CK_RV 339 soft_digest_final(soft_session_t *session_p, CK_BYTE_PTR pDigest, 340 CK_ULONG_PTR pulDigestLen) 341 { 342 343 return (soft_digest_common(session_p, NULL, 0, 344 pDigest, pulDigestLen)); 345 } 346 347 /* 348 * Perform digest init operation internally for the support of 349 * CKM_MD5_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA1_KEY_DERIVATION 350 * and CKM_MD5_KEY_DERIVATION mechanisms. 351 * 352 * This function is called with the session being held, and without 353 * its mutex taken. 354 */ 355 CK_RV 356 soft_digest_init_internal(soft_session_t *session_p, CK_MECHANISM_PTR 357 pMechanism) 358 { 359 360 CK_RV rv; 361 362 (void) pthread_mutex_lock(&session_p->session_mutex); 363 364 /* Check to see if digest operation is already active */ 365 if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) { 366 (void) pthread_mutex_unlock(&session_p->session_mutex); 367 return (CKR_OPERATION_ACTIVE); 368 } 369 370 session_p->digest.flags = CRYPTO_OPERATION_ACTIVE; 371 372 (void) pthread_mutex_unlock(&session_p->session_mutex); 373 374 rv = soft_digest_init(session_p, pMechanism); 375 376 if (rv != CKR_OK) { 377 (void) pthread_mutex_lock(&session_p->session_mutex); 378 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE; 379 (void) pthread_mutex_unlock(&session_p->session_mutex); 380 } 381 382 return (rv); 383 } 384 385 /* 386 * Call soft_digest_update() function with the value of a secret key. 387 */ 388 CK_RV 389 soft_digest_key(soft_session_t *session_p, soft_object_t *key_p) 390 { 391 392 CK_RV rv; 393 394 /* Only secret key is allowed to be digested */ 395 if (key_p->class != CKO_SECRET_KEY) 396 return (CKR_KEY_INDIGESTIBLE); 397 398 if ((OBJ_SEC_VALUE(key_p) == NULL) || 399 (OBJ_SEC_VALUE_LEN(key_p) == 0)) 400 return (CKR_KEY_SIZE_RANGE); 401 402 rv = soft_digest_update(session_p, OBJ_SEC_VALUE(key_p), 403 OBJ_SEC_VALUE_LEN(key_p)); 404 405 return (rv); 406 407 } 408