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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <strings.h>
  27 #include <md5.h>
  28 #include <pthread.h>
  29 #include <stdlib.h>
  30 #include <sys/sha1.h>
  31 #include <sys/sha2.h>
  32 #include <sys/types.h>
  33 #include <security/cryptoki.h>
  34 #include "softGlobal.h"
  35 #include "softOps.h"
  36 #include "softSession.h"
  37 #include "softObject.h"
  38 
  39 
  40 /*
  41  * soft_digest_init()
  42  *
  43  * Arguments:
  44  *      session_p:      pointer to soft_session_t struct
  45  *      pMechanism:     pointer to CK_MECHANISM struct provided by application
  46  *
  47  * Description:
  48  *      called by C_DigestInit(). This function allocates space for
  49  *      context, then calls the corresponding software provided digest
  50  *      init routine based on the mechanism.
  51  *
  52  * Returns:
  53  *      CKR_OK: success
  54  *      CKR_HOST_MEMORY: run out of system memory
  55  *      CKR_MECHANISM_INVALID: invalid mechanism type
  56  */
  57 CK_RV
  58 soft_digest_init(soft_session_t *session_p, CK_MECHANISM_PTR pMechanism)
  59 {
  60 
  61         switch (pMechanism->mechanism) {
  62 
  63         case CKM_MD5:
  64                 (void) pthread_mutex_lock(&session_p->session_mutex);
  65 
  66                 session_p->digest.context = malloc(sizeof (MD5_CTX));
  67 
  68                 if (session_p->digest.context == NULL) {
  69                         (void) pthread_mutex_unlock(&session_p->session_mutex);
  70                         return (CKR_HOST_MEMORY);
  71                 }
  72 
  73                 session_p->digest.mech.mechanism = CKM_MD5;
  74                 (void) pthread_mutex_unlock(&session_p->session_mutex);
  75 
  76                 MD5Init((MD5_CTX *)session_p->digest.context);
  77 
  78                 break;
  79 
  80         case CKM_SHA_1:
  81 
  82                 (void) pthread_mutex_lock(&session_p->session_mutex);
  83 
  84                 session_p->digest.context = malloc(sizeof (SHA1_CTX));
  85 
  86                 if (session_p->digest.context == NULL) {
  87                         (void) pthread_mutex_unlock(&session_p->session_mutex);
  88                         return (CKR_HOST_MEMORY);
  89                 }
  90 
  91                 session_p->digest.mech.mechanism = CKM_SHA_1;
  92                 session_p->digest.mech.pParameter = pMechanism->pParameter;
  93                 session_p->digest.mech.ulParameterLen =
  94                     pMechanism->ulParameterLen;
  95                 (void) pthread_mutex_unlock(&session_p->session_mutex);
  96 
  97                 SHA1Init((SHA1_CTX *)session_p->digest.context);
  98 
  99                 break;
 100 
 101         case CKM_SHA256:
 102         case CKM_SHA384:
 103         case CKM_SHA512:
 104 
 105                 (void) pthread_mutex_lock(&session_p->session_mutex);
 106 
 107                 session_p->digest.context = malloc(sizeof (SHA2_CTX));
 108 
 109                 if (session_p->digest.context == NULL) {
 110                         (void) pthread_mutex_unlock(&session_p->session_mutex);
 111                         return (CKR_HOST_MEMORY);
 112                 }
 113 
 114                 switch (pMechanism->mechanism) {
 115                 case CKM_SHA256:
 116                         session_p->digest.mech.mechanism = CKM_SHA256;
 117                         (void) pthread_mutex_unlock(&session_p->session_mutex);
 118                         SHA2Init(SHA256,
 119                             (SHA2_CTX *)session_p->digest.context);
 120                         break;
 121 
 122                 case CKM_SHA384:
 123                         session_p->digest.mech.mechanism = CKM_SHA384;
 124                         (void) pthread_mutex_unlock(&session_p->session_mutex);
 125                         SHA2Init(SHA384,
 126                             (SHA2_CTX *)session_p->digest.context);
 127                         break;
 128 
 129                 case CKM_SHA512:
 130                         session_p->digest.mech.mechanism = CKM_SHA512;
 131                         (void) pthread_mutex_unlock(&session_p->session_mutex);
 132                         SHA2Init(SHA512,
 133                             (SHA2_CTX *)session_p->digest.context);
 134                         break;
 135                 }
 136                 break;
 137 
 138         default:
 139                 return (CKR_MECHANISM_INVALID);
 140         }
 141 
 142         return (CKR_OK);
 143 }
 144 
 145 
 146 /*
 147  * soft_digest_common()
 148  *
 149  * Arguments:
 150  *      session_p:      pointer to soft_session_t struct
 151  *      pData:          pointer to the input data to be digested
 152  *      ulDataLen:      length of the input data
 153  *      pDigest:        pointer to the output data after digesting
 154  *      pulDigestLen:   length of the output data
 155  *
 156  * Description:
 157  *      called by soft_digest() or soft_digest_final(). This function
 158  *      determines the length of output buffer and calls the corresponding
 159  *      software provided digest routine based on the mechanism.
 160  *
 161  * Returns:
 162  *      CKR_OK: success
 163  *      CKR_MECHANISM_INVALID: invalid mechanism type
 164  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
 165  *                            is too small
 166  */
 167 CK_RV
 168 soft_digest_common(soft_session_t *session_p, CK_BYTE_PTR pData,
 169         CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
 170 {
 171 
 172         CK_ULONG digestLen = 0;
 173         size_t len = 0;
 174 
 175         /*
 176          * Determine the output data length based on the mechanism
 177          */
 178         switch (session_p->digest.mech.mechanism) {
 179 
 180         case CKM_MD5:
 181                 digestLen = 16;
 182                 break;
 183 
 184         case CKM_SHA_1:
 185                 digestLen = 20;
 186                 break;
 187 
 188         case CKM_SHA256:
 189                 digestLen = 32;
 190                 break;
 191 
 192         case CKM_SHA384:
 193                 digestLen = 48;
 194                 break;
 195 
 196         case CKM_SHA512:
 197                 digestLen = 64;
 198                 break;
 199 
 200         default:
 201                 return (CKR_MECHANISM_INVALID);
 202         }
 203 
 204         if (pDigest == NULL) {
 205                 /*
 206                  * Application only wants to know the length of the
 207                  * buffer needed to hold the message digest.
 208                  */
 209                 *pulDigestLen = digestLen;
 210                 return (CKR_OK);
 211         }
 212 
 213         if (*pulDigestLen < digestLen) {
 214                 /*
 215                  * Application provides buffer too small to hold the
 216                  * digest message. Return the length of buffer needed
 217                  * to the application.
 218                  */
 219                 *pulDigestLen = digestLen;
 220                 return (CKR_BUFFER_TOO_SMALL);
 221         }
 222 
 223         /*
 224          * Call the corresponding system provided software digest routine.
 225          * If the soft_digest_common() is called by soft_digest_final()
 226          * the pData is NULL, and the ulDataLen is zero.
 227          */
 228         switch (session_p->digest.mech.mechanism) {
 229 
 230         case CKM_MD5:
 231                 if (pData != NULL) {
 232                         /*
 233                          * this is called by soft_digest()
 234                          */
 235 #ifdef  __sparcv9
 236                         MD5Update((MD5_CTX *)session_p->digest.context,
 237                             /* LINTED */
 238                             pData, (uint_t)ulDataLen);
 239 #else   /* !__sparcv9 */
 240                         MD5Update((MD5_CTX *)session_p->digest.context,
 241                             pData, ulDataLen);
 242 #endif  /* __sparcv9 */
 243                         MD5Final(pDigest, (MD5_CTX *)session_p->digest.context);
 244                 } else {
 245                         /*
 246                          * this is called by soft_digest_final()
 247                          */
 248                         MD5Final(pDigest, (MD5_CTX *)session_p->digest.context);
 249                         len = sizeof (MD5_CTX);
 250                 }
 251                 break;
 252 
 253         case CKM_SHA_1:
 254                 if (pData != NULL) {
 255                         /*
 256                          * this is called by soft_digest()
 257                          */
 258 
 259 #ifdef  __sparcv9
 260                         SHA1Update((SHA1_CTX *)session_p->digest.context,
 261                             /* LINTED */
 262                             pData, (uint32_t)ulDataLen);
 263 #else   /* !__sparcv9 */
 264                         SHA1Update((SHA1_CTX *)session_p->digest.context,
 265                             pData, ulDataLen);
 266 #endif  /* __sparcv9 */
 267                         SHA1Final(pDigest,
 268                             (SHA1_CTX *)session_p->digest.context);
 269                 } else {
 270                         /*
 271                          * this is called by soft_digest_final()
 272                          */
 273                         SHA1Final(pDigest,
 274                             (SHA1_CTX *)session_p->digest.context);
 275                         len = sizeof (SHA1_CTX);
 276                 }
 277                 break;
 278         case CKM_SHA256:
 279         case CKM_SHA384:
 280         case CKM_SHA512:
 281                 if (pData != NULL) {
 282                         /*
 283                          * this is called by soft_digest()
 284                          */
 285 
 286                         SHA2Update((SHA2_CTX *)session_p->digest.context,
 287                             pData, ulDataLen);
 288 
 289                         SHA2Final(pDigest,
 290                             (SHA2_CTX *)session_p->digest.context);
 291                 } else {
 292                         /*
 293                          * this is called by soft_digest_final()
 294                          */
 295                         SHA2Final(pDigest,
 296                             (SHA2_CTX *)session_p->digest.context);
 297                         len = sizeof (SHA2_CTX);
 298                 }
 299 
 300                 break;
 301         }
 302 
 303         /* Paranoia on behalf of C_DigestKey callers: bzero the context */
 304         if (session_p->digest.flags & CRYPTO_KEY_DIGESTED) {
 305                 bzero(session_p->digest.context, len);
 306                 session_p->digest.flags &= ~CRYPTO_KEY_DIGESTED;
 307         }
 308         *pulDigestLen = digestLen;
 309         (void) pthread_mutex_lock(&session_p->session_mutex);
 310         free(session_p->digest.context);
 311         session_p->digest.context = NULL;
 312         (void) pthread_mutex_unlock(&session_p->session_mutex);
 313 
 314         return (CKR_OK);
 315 }
 316 
 317 
 318 /*
 319  * soft_digest()
 320  *
 321  * Arguments:
 322  *      session_p:      pointer to soft_session_t struct
 323  *      pData:          pointer to the input data to be digested
 324  *      ulDataLen:      length of the input data
 325  *      pDigest:        pointer to the output data after digesting
 326  *      pulDigestLen:   length of the output data
 327  *
 328  * Description:
 329  *      called by C_Digest(). This function calls soft_digest_common().
 330  *
 331  * Returns:
 332  *      see return values in soft_digest_common().
 333  */
 334 CK_RV
 335 soft_digest(soft_session_t *session_p, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
 336         CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
 337 {
 338 
 339         return (soft_digest_common(session_p, pData, ulDataLen,
 340             pDigest, pulDigestLen));
 341 }
 342 
 343 
 344 /*
 345  * soft_digest_update()
 346  *
 347  * Arguments:
 348  *      session_p:      pointer to soft_session_t struct
 349  *      pPart:          pointer to the input data to be digested
 350  *      ulPartLen:      length of the input data
 351  *
 352  * Description:
 353  *      called by C_DigestUpdate(). This function calls the corresponding
 354  *      software provided digest update routine based on the mechanism.
 355  *
 356  * Returns:
 357  *      CKR_OK: success
 358  *      CKR_MECHANISM_INVALID: invalid MECHANISM type.
 359  */
 360 CK_RV
 361 soft_digest_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
 362         CK_ULONG ulPartLen)
 363 {
 364 
 365         switch (session_p->digest.mech.mechanism) {
 366 
 367         case CKM_MD5:
 368 #ifdef  __sparcv9
 369                 MD5Update((MD5_CTX *)session_p->digest.context,
 370                     /* LINTED */
 371                     pPart, (uint_t)ulPartLen);
 372 #else   /* !__sparcv9 */
 373                 MD5Update((MD5_CTX *)session_p->digest.context,
 374                     pPart, ulPartLen);
 375 #endif  /* __sparcv9 */
 376                 break;
 377 
 378         case CKM_SHA_1:
 379 #ifdef  __sparcv9
 380                 SHA1Update((SHA1_CTX *)session_p->digest.context,
 381                     /* LINTED */
 382                     pPart, (uint32_t)ulPartLen);
 383 #else   /* !__sparcv9 */
 384                 SHA1Update((SHA1_CTX *)session_p->digest.context,
 385                     pPart, ulPartLen);
 386 #endif  /* __sparcv9 */
 387                 break;
 388 
 389         case CKM_SHA256:
 390         case CKM_SHA384:
 391         case CKM_SHA512:
 392                 SHA2Update((SHA2_CTX *)session_p->digest.context,
 393                     pPart, ulPartLen);
 394                 break;
 395 
 396         default:
 397                 return (CKR_MECHANISM_INVALID);
 398         }
 399 
 400         return (CKR_OK);
 401 }
 402 
 403 
 404 /*
 405  * soft_digest_final()
 406  *
 407  * Arguments:
 408  *      session_p:      pointer to soft_session_t struct
 409  *      pDigest:        pointer to the output data after digesting
 410  *      pulDigestLen:   length of the output data
 411  *
 412  * Description:
 413  *      called by C_DigestFinal(). This function calls soft_digest_common().
 414  *
 415  * Returns:
 416  *      see return values in soft_digest_common().
 417  */
 418 CK_RV
 419 soft_digest_final(soft_session_t *session_p, CK_BYTE_PTR pDigest,
 420         CK_ULONG_PTR pulDigestLen)
 421 {
 422 
 423         return (soft_digest_common(session_p, NULL, 0,
 424             pDigest, pulDigestLen));
 425 }
 426 
 427 /*
 428  * Perform digest init operation internally for the support of
 429  * CKM_MD5_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA1_KEY_DERIVATION
 430  * and CKM_MD5_KEY_DERIVATION mechanisms.
 431  *
 432  * This function is called with the session being held, and without
 433  * its mutex taken.
 434  */
 435 CK_RV
 436 soft_digest_init_internal(soft_session_t *session_p, CK_MECHANISM_PTR
 437         pMechanism)
 438 {
 439 
 440         CK_RV rv;
 441 
 442         (void) pthread_mutex_lock(&session_p->session_mutex);
 443 
 444         /* Check to see if digest operation is already active */
 445         if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
 446                 (void) pthread_mutex_unlock(&session_p->session_mutex);
 447                 return (CKR_OPERATION_ACTIVE);
 448         }
 449 
 450         session_p->digest.flags = CRYPTO_OPERATION_ACTIVE;
 451 
 452         (void) pthread_mutex_unlock(&session_p->session_mutex);
 453 
 454         rv = soft_digest_init(session_p, pMechanism);
 455 
 456         if (rv != CKR_OK) {
 457                 (void) pthread_mutex_lock(&session_p->session_mutex);
 458                 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
 459                 (void) pthread_mutex_unlock(&session_p->session_mutex);
 460         }
 461 
 462         return (rv);
 463 }
 464 
 465 /*
 466  * Call soft_digest_update() function with the value of a secret key.
 467  */
 468 CK_RV
 469 soft_digest_key(soft_session_t *session_p, soft_object_t *key_p)
 470 {
 471 
 472         CK_RV rv;
 473 
 474         /* Only secret key is allowed to be digested */
 475         if (key_p->class != CKO_SECRET_KEY)
 476                 return (CKR_KEY_INDIGESTIBLE);
 477 
 478         if ((OBJ_SEC_VALUE(key_p) == NULL) ||
 479             (OBJ_SEC_VALUE_LEN(key_p) == 0))
 480                 return (CKR_KEY_SIZE_RANGE);
 481 
 482         rv = soft_digest_update(session_p, OBJ_SEC_VALUE(key_p),
 483             OBJ_SEC_VALUE_LEN(key_p));
 484 
 485         return (rv);
 486 
 487 }
 488 
 489 /*
 490  * This function releases allocated digest context. The caller
 491  * may (lock_held == B_TRUE) or may not (lock_held == B_FALSE)
 492  * hold a session mutex.
 493  */
 494 void
 495 soft_digest_cleanup(soft_session_t *session_p, boolean_t lock_held)
 496 {
 497         boolean_t lock_true = B_TRUE;
 498 
 499         if (!lock_held)
 500                 (void) pthread_mutex_lock(&session_p->session_mutex);
 501 
 502         if (session_p->digest.context != NULL) {
 503                 free(session_p->digest.context);
 504                 session_p->digest.context = NULL;
 505         }
 506 
 507         session_p->digest.flags = 0;
 508 
 509         if (!lock_held)
 510                 SES_REFRELE(session_p, lock_true);
 511 
 512 }