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