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