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 }