1/*
2 * The Initial Developer of the Original Code is International
3 * Business Machines Corporation. Portions created by IBM
4 * Corporation are Copyright (C) 2005 International Business
5 * Machines Corporation. All Rights Reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the Common Public License as published by
9 * IBM Corporation; either version 1 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * Common Public License for more details.
16 *
17 * You should have received a copy of the Common Public License
18 * along with this program; if not, a copy can be viewed at
19 * http://www.opensource.org/licenses/cpl1.0.php.
20 */
21
22/* (C) COPYRIGHT International Business Machines Corp. 2001, 2002, 2005 */
23/*
24 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#include "tpmtok_int.h"
29
30CK_RV
31sign_mgr_init(SESSION		* sess,
32	SIGN_VERIFY_CONTEXT    * ctx,
33	CK_MECHANISM	   * mech,
34	CK_BBOOL		 recover_mode,
35	CK_OBJECT_HANDLE	 key)
36{
37	OBJECT	  * key_obj = NULL;
38	CK_ATTRIBUTE    * attr    = NULL;
39	CK_BYTE	 * ptr	= NULL;
40	CK_KEY_TYPE	keytype;
41	CK_OBJECT_CLASS   class;
42	CK_BBOOL	  flag;
43	CK_RV		rc;
44
45	if (! sess || ! ctx) {
46		return (CKR_FUNCTION_FAILED);
47	}
48	if (ctx->active != FALSE) {
49		return (CKR_OPERATION_ACTIVE);
50	}
51
52	rc = object_mgr_find_in_map1(sess->hContext, key, &key_obj);
53	if (rc != CKR_OK) {
54		return (CKR_KEY_HANDLE_INVALID);
55	}
56	rc = template_attribute_find(key_obj->template, CKA_SIGN, &attr);
57	if (rc == FALSE) {
58		return (CKR_KEY_TYPE_INCONSISTENT);
59	} else {
60		flag = *(CK_BBOOL *)attr->pValue;
61		if (flag != TRUE) {
62			return (CKR_KEY_FUNCTION_NOT_PERMITTED);
63		}
64	}
65
66	switch (mech->mechanism) {
67		case CKM_RSA_PKCS:
68		{
69			rc = template_attribute_find(key_obj->template,
70			    CKA_KEY_TYPE, &attr);
71			if (rc == FALSE) {
72				return (CKR_KEY_TYPE_INCONSISTENT);
73			} else {
74				keytype = *(CK_KEY_TYPE *)attr->pValue;
75				if (keytype != CKK_RSA) {
76					return (CKR_KEY_TYPE_INCONSISTENT);
77				}
78			}
79
80			// must be a PRIVATE key
81			//
82			flag = template_attribute_find(key_obj->template,
83			    CKA_CLASS, &attr);
84			if (flag == FALSE) {
85				return (CKR_KEY_TYPE_INCONSISTENT);
86			}
87			else
88				class = *(CK_OBJECT_CLASS *)attr->pValue;
89
90			if (class != CKO_PRIVATE_KEY) {
91				return (CKR_KEY_TYPE_INCONSISTENT);
92			}
93			// PKCS #11 doesn't allow multi - part RSA operations
94			//
95			ctx->context_len = 0;
96			ctx->context	= NULL;
97		}
98		break;
99		case CKM_MD5_RSA_PKCS:
100		case CKM_SHA1_RSA_PKCS:
101		{
102			rc = template_attribute_find(key_obj->template,
103			    CKA_KEY_TYPE, &attr);
104			if (rc == FALSE) {
105				return (CKR_KEY_TYPE_INCONSISTENT);
106			} else {
107				keytype = *(CK_KEY_TYPE *)attr->pValue;
108				if (keytype != CKK_RSA) {
109					return (CKR_KEY_TYPE_INCONSISTENT);
110				}
111			}
112
113			// must be a PRIVATE key operation
114			//
115			flag = template_attribute_find(key_obj->template,
116			    CKA_CLASS, &attr);
117			if (flag == FALSE) {
118				return (CKR_FUNCTION_FAILED);
119			}
120			else
121				class = *(CK_OBJECT_CLASS *)attr->pValue;
122
123			if (class != CKO_PRIVATE_KEY) {
124				return (CKR_FUNCTION_FAILED);
125			}
126			ctx->context_len = sizeof (RSA_DIGEST_CONTEXT);
127			ctx->context = (CK_BYTE *)malloc(
128			    sizeof (RSA_DIGEST_CONTEXT));
129			if (! ctx->context) {
130				return (CKR_HOST_MEMORY);
131			}
132			(void) memset(ctx->context, 0x0,
133			    sizeof (RSA_DIGEST_CONTEXT));
134		}
135		break;
136		case CKM_MD5_HMAC:
137		case CKM_SHA_1_HMAC:
138		{
139			if (mech->ulParameterLen != 0) {
140				return (CKR_MECHANISM_PARAM_INVALID);
141			}
142			rc = template_attribute_find(key_obj->template,
143			    CKA_KEY_TYPE, &attr);
144			if (rc == FALSE) {
145				return (CKR_KEY_TYPE_INCONSISTENT);
146			} else {
147				keytype = *(CK_KEY_TYPE *)attr->pValue;
148				if (keytype != CKK_GENERIC_SECRET) {
149					return (CKR_KEY_TYPE_INCONSISTENT);
150				}
151			}
152
153			// PKCS #11 doesn't allow multi - part HMAC operations
154			//
155			ctx->context_len = 0;
156			ctx->context	= NULL;
157		}
158		break;
159
160		case CKM_MD5_HMAC_GENERAL:
161		case CKM_SHA_1_HMAC_GENERAL:
162		{
163			CK_MAC_GENERAL_PARAMS *param =
164			    (CK_MAC_GENERAL_PARAMS *)mech->pParameter;
165
166			if (mech->ulParameterLen !=
167			    sizeof (CK_MAC_GENERAL_PARAMS)) {
168				return (CKR_MECHANISM_PARAM_INVALID);
169			}
170
171			if ((mech->mechanism == CKM_MD5_HMAC_GENERAL) &&
172			    (*param > 16)) {
173				return (CKR_MECHANISM_PARAM_INVALID);
174			}
175			if ((mech->mechanism == CKM_SHA_1_HMAC_GENERAL) &&
176			    (*param > 20)) {
177				return (CKR_MECHANISM_PARAM_INVALID);
178			}
179			rc = template_attribute_find(key_obj->template,
180			    CKA_KEY_TYPE, &attr);
181			if (rc == FALSE) {
182				return (CKR_KEY_TYPE_INCONSISTENT);
183			} else {
184				keytype = *(CK_KEY_TYPE *)attr->pValue;
185				if (keytype != CKK_GENERIC_SECRET) {
186					return (CKR_KEY_TYPE_INCONSISTENT);
187				}
188			}
189
190			// PKCS #11 doesn't allow multi - part HMAC operations
191			//
192			ctx->context_len = 0;
193			ctx->context	= NULL;
194		}
195		break;
196		default:
197			return (CKR_MECHANISM_INVALID);
198	}
199
200	if (mech->ulParameterLen > 0 && mech->pParameter == NULL)
201		return (CKR_ARGUMENTS_BAD);
202
203	if (mech->ulParameterLen > 0) {
204		ptr = (CK_BYTE *)malloc(mech->ulParameterLen);
205		if (! ptr) {
206			return (CKR_HOST_MEMORY);
207		}
208		(void) memcpy(ptr, mech->pParameter, mech->ulParameterLen);
209	}
210
211	ctx->key		 = key;
212	ctx->mech.ulParameterLen = mech->ulParameterLen;
213	ctx->mech.mechanism	= mech->mechanism;
214	ctx->mech.pParameter	= ptr;
215	ctx->multi		= FALSE;
216	ctx->active		= TRUE;
217	ctx->recover		= recover_mode;
218
219	return (CKR_OK);
220}
221
222CK_RV
223sign_mgr_cleanup(SIGN_VERIFY_CONTEXT *ctx)
224{
225	if (! ctx) {
226		return (CKR_FUNCTION_FAILED);
227	}
228	ctx->key		 = 0;
229	ctx->mech.ulParameterLen = 0;
230	ctx->mech.mechanism	= 0;
231	ctx->multi		= FALSE;
232	ctx->active		= FALSE;
233	ctx->recover		= FALSE;
234	ctx->context_len	 = 0;
235
236	if (ctx->mech.pParameter) {
237		free(ctx->mech.pParameter);
238		ctx->mech.pParameter = NULL;
239	}
240
241	if (ctx->context) {
242		free(ctx->context);
243		ctx->context = NULL;
244	}
245
246	return (CKR_OK);
247}
248
249CK_RV
250sign_mgr_sign(SESSION	* sess,
251	CK_BBOOL	length_only,
252	SIGN_VERIFY_CONTEXT  * ctx,
253	CK_BYTE		* in_data,
254	CK_ULONG	in_data_len,
255	CK_BYTE		* out_data,
256	CK_ULONG	* out_data_len)
257{
258	if (! sess || ! ctx) {
259		return (CKR_FUNCTION_FAILED);
260	}
261	if (ctx->active == FALSE) {
262		return (CKR_OPERATION_NOT_INITIALIZED);
263	}
264	if (ctx->recover == TRUE) {
265		return (CKR_OPERATION_NOT_INITIALIZED);
266	}
267
268	// if the caller just wants the signature length, there is no reason to
269	// specify the input data.  I just need the input data length
270	//
271	if ((length_only == FALSE) && (! in_data || ! out_data)) {
272		return (CKR_FUNCTION_FAILED);
273	}
274	if (ctx->multi == TRUE) {
275		return (CKR_OPERATION_ACTIVE);
276	}
277	switch (ctx->mech.mechanism) {
278		case CKM_RSA_PKCS:
279		return (rsa_pkcs_sign(sess,	length_only,  ctx,
280		    in_data,  in_data_len,
281		    out_data, out_data_len));
282		case CKM_MD5_RSA_PKCS:
283		case CKM_SHA1_RSA_PKCS:
284		return (rsa_hash_pkcs_sign(sess,	length_only, ctx,
285		    in_data,  in_data_len,
286		    out_data, out_data_len));
287
288		case CKM_MD5_HMAC:
289		case CKM_MD5_HMAC_GENERAL:
290		return (md5_hmac_sign(sess,	length_only, ctx,
291		    in_data,  in_data_len,
292		    out_data, out_data_len));
293		case CKM_SHA_1_HMAC:
294		case CKM_SHA_1_HMAC_GENERAL:
295		return (sha1_hmac_sign(sess,	length_only, ctx,
296		    in_data,  in_data_len,
297		    out_data, out_data_len));
298		default:
299			return (CKR_MECHANISM_INVALID);
300	}
301}
302
303CK_RV
304sign_mgr_sign_update(SESSION		* sess,
305	SIGN_VERIFY_CONTEXT * ctx,
306	CK_BYTE		* in_data,
307	CK_ULONG		in_data_len)
308{
309	if (! sess || ! ctx || ! in_data) {
310		return (CKR_FUNCTION_FAILED);
311	}
312
313	if (ctx->active == FALSE) {
314		return (CKR_OPERATION_NOT_INITIALIZED);
315	}
316	if (ctx->recover == TRUE) {
317		return (CKR_OPERATION_NOT_INITIALIZED);
318	}
319	ctx->multi = TRUE;
320
321	switch (ctx->mech.mechanism) {
322		case CKM_MD5_RSA_PKCS:
323		case CKM_SHA1_RSA_PKCS:
324			return (rsa_hash_pkcs_sign_update(sess, ctx,
325			    in_data, in_data_len));
326		default:
327			return (CKR_MECHANISM_INVALID);
328	}
329}
330
331CK_RV
332sign_mgr_sign_final(SESSION		* sess,
333	CK_BBOOL		length_only,
334	SIGN_VERIFY_CONTEXT * ctx,
335	CK_BYTE		* signature,
336	CK_ULONG	    * sig_len)
337{
338	if (! sess || ! ctx) {
339		return (CKR_FUNCTION_FAILED);
340	}
341	if (ctx->active == FALSE) {
342		return (CKR_OPERATION_NOT_INITIALIZED);
343	}
344	if (ctx->recover == TRUE) {
345		return (CKR_OPERATION_NOT_INITIALIZED);
346	}
347	switch (ctx->mech.mechanism) {
348		case CKM_MD5_RSA_PKCS:
349		case CKM_SHA1_RSA_PKCS:
350			return (rsa_hash_pkcs_sign_final(sess, length_only,
351			    ctx, signature, sig_len));
352		default:
353		return (CKR_MECHANISM_INVALID);
354	}
355}
356
357CK_RV
358sign_mgr_sign_recover(SESSION		* sess,
359	CK_BBOOL		length_only,
360	SIGN_VERIFY_CONTEXT * ctx,
361	CK_BYTE		* in_data,
362	CK_ULONG		in_data_len,
363	CK_BYTE		* out_data,
364	CK_ULONG	    * out_data_len)
365{
366	if (! sess || ! ctx) {
367		return (CKR_FUNCTION_FAILED);
368	}
369	if (ctx->active == FALSE) {
370		return (CKR_OPERATION_NOT_INITIALIZED);
371	}
372	if (ctx->recover == FALSE) {
373		return (CKR_OPERATION_NOT_INITIALIZED);
374	}
375
376	// if the caller just wants the signature length, there is no reason to
377	// specify the input data.  I just need the input data length
378	//
379	if ((length_only == FALSE) && (! in_data || ! out_data)) {
380		return (CKR_FUNCTION_FAILED);
381	}
382	if (ctx->multi == TRUE) {
383		return (CKR_OPERATION_ACTIVE);
384	}
385	switch (ctx->mech.mechanism) {
386		case CKM_RSA_PKCS:
387			return (rsa_pkcs_sign(sess,	length_only,  ctx,
388			    in_data,  in_data_len,
389			    out_data, out_data_len));
390		default:
391			return (CKR_MECHANISM_INVALID);
392	}
393}
394