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
do_soft_digest(void ** s,CK_MECHANISM_PTR pMechanism,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen,int opflag)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
do_soft_hmac_init(void ** s,CK_MECHANISM_PTR pMechanism,CK_BYTE_PTR kval,CK_ULONG klen,int opflag)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
do_soft_hmac_update(void ** s,CK_BYTE_PTR pData,CK_ULONG ulDataLen,int opflag)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
do_soft_hmac_sign(void ** s,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG_PTR pulSignatureLen,int opflag)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
do_soft_hmac_verify(void ** s,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,int opflag)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
free_soft_ctx(void * s,int opflag)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 }
251