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