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 }