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