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#include "tpmtok_int.h"
28
29CK_RV
30sha1_hash(SESSION *sess,
31	CK_BBOOL length_only,
32	DIGEST_CONTEXT  *ctx,
33	CK_BYTE	 *in_data,
34	CK_ULONG in_data_len,
35	CK_BYTE	 *out_data,
36	CK_ULONG *out_data_len)
37{
38	if (! sess || ! ctx || ! out_data_len) {
39		return (CKR_FUNCTION_FAILED);
40	}
41	*out_data_len = SHA1_DIGEST_LENGTH;
42	if (length_only == TRUE) {
43		return (CKR_OK);
44	}
45
46	if (ctx->context.sha1ctx == NULL)
47		return (CKR_HOST_MEMORY);
48	SHA1Update(ctx->context.sha1ctx, in_data, in_data_len);
49
50	SHA1Final(out_data, ctx->context.sha1ctx);
51
52	return (CKR_OK);
53}
54
55CK_RV
56sha1_hmac_sign(SESSION		* sess,
57	CK_BBOOL		length_only,
58	SIGN_VERIFY_CONTEXT  * ctx,
59	CK_BYTE		* in_data,
60	CK_ULONG		in_data_len,
61	CK_BYTE		* out_data,
62	CK_ULONG		* out_data_len) {
63	OBJECT	  * key_obj = NULL;
64	CK_ATTRIBUTE    * attr    = NULL;
65	CK_BYTE	   hash[SHA1_DIGEST_LENGTH];
66	DIGEST_CONTEXT    digest_ctx;
67	CK_MECHANISM	digest_mech;
68	CK_BYTE	   k_ipad[SHA1_BLOCK_SIZE];
69	CK_BYTE	   k_opad[SHA1_BLOCK_SIZE];
70	CK_ULONG	  key_bytes, hash_len, hmac_len;
71	CK_ULONG	  i;
72	CK_RV		rc;
73
74	if (! sess || ! ctx || ! out_data_len) {
75		return (CKR_FUNCTION_FAILED);
76	}
77
78	if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL) {
79		hmac_len = *(CK_ULONG *)ctx->mech.pParameter;
80
81		if (hmac_len == 0) {
82			*out_data_len = 0;
83			return (CKR_OK);
84		}
85	} else {
86		hmac_len = SHA1_DIGEST_LENGTH;
87	}
88
89	*out_data_len = hmac_len;
90	if (length_only == TRUE) {
91		return (CKR_OK);
92	}
93
94	(void) memset(&digest_ctx, 0x0, sizeof (DIGEST_CONTEXT));
95
96	rc = object_mgr_find_in_map1(sess->hContext, ctx->key, &key_obj);
97	if (rc != CKR_OK) {
98		return (rc);
99	}
100	rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr);
101	if (rc == FALSE) {
102		return (CKR_FUNCTION_FAILED);
103	} else
104		key_bytes = attr->ulValueLen;
105
106
107	if (key_bytes > SHA1_BLOCK_SIZE) {
108		digest_mech.mechanism	= CKM_SHA_1;
109		digest_mech.ulParameterLen = 0;
110		digest_mech.pParameter	= NULL;
111
112		rc = digest_mgr_init(sess, &digest_ctx, &digest_mech);
113		if (rc != CKR_OK) {
114			(void) digest_mgr_cleanup(&digest_ctx);
115			return (rc);
116		}
117
118		hash_len = sizeof (hash);
119		rc = digest_mgr_digest(sess, FALSE, &digest_ctx,
120		    attr->pValue, attr->ulValueLen, hash,  &hash_len);
121		if (rc != CKR_OK) {
122			(void) digest_mgr_cleanup(&digest_ctx);
123			return (rc);
124		}
125
126		(void) digest_mgr_cleanup(&digest_ctx);
127		(void) memset(&digest_ctx, 0x0, sizeof (DIGEST_CONTEXT));
128
129		for (i = 0; i < hash_len; i++) {
130			k_ipad[i] = hash[i] ^ 0x36;
131			k_opad[i] = hash[i] ^ 0x5C;
132		}
133
134		(void) memset(&k_ipad[i], 0x36, SHA1_BLOCK_SIZE - i);
135		(void) memset(&k_opad[i], 0x5C, SHA1_BLOCK_SIZE - i);
136	} else {
137		CK_BYTE *key = attr->pValue;
138
139		for (i = 0; i < key_bytes; i++) {
140			k_ipad[i] = key[i] ^ 0x36;
141			k_opad[i] = key[i] ^ 0x5C;
142		}
143
144		(void) memset(&k_ipad[i], 0x36, SHA1_BLOCK_SIZE - key_bytes);
145		(void) memset(&k_opad[i], 0x5C, SHA1_BLOCK_SIZE - key_bytes);
146	}
147
148	digest_mech.mechanism	= CKM_SHA_1;
149	digest_mech.ulParameterLen = 0;
150	digest_mech.pParameter	= NULL;
151
152	if (rc != CKR_OK) {
153		(void) digest_mgr_cleanup(&digest_ctx);
154		return (rc);
155	}
156
157	rc = digest_mgr_digest_update(sess, &digest_ctx,
158	    k_ipad, SHA1_BLOCK_SIZE);
159	if (rc != CKR_OK) {
160		(void) digest_mgr_cleanup(&digest_ctx);
161		return (rc);
162	}
163
164	rc = digest_mgr_digest_update(sess, &digest_ctx, in_data, in_data_len);
165	if (rc != CKR_OK) {
166		(void) digest_mgr_cleanup(&digest_ctx);
167		return (rc);
168	}
169
170	hash_len = sizeof (hash);
171	rc = digest_mgr_digest_final(sess, &digest_ctx, hash, &hash_len);
172	if (rc != CKR_OK) {
173		(void) digest_mgr_cleanup(&digest_ctx);
174		return (rc);
175	}
176
177	(void) digest_mgr_cleanup(&digest_ctx);
178	(void) memset(&digest_ctx, 0x0, sizeof (DIGEST_CONTEXT));
179
180	rc = digest_mgr_init(sess, &digest_ctx, &digest_mech);
181	if (rc != CKR_OK) {
182		(void) digest_mgr_cleanup(&digest_ctx);
183		return (rc);
184	}
185
186	rc = digest_mgr_digest_update(sess, &digest_ctx,
187	    k_opad, SHA1_BLOCK_SIZE);
188	if (rc != CKR_OK) {
189		(void) digest_mgr_cleanup(&digest_ctx);
190		return (rc);
191	}
192
193	rc = digest_mgr_digest_update(sess, &digest_ctx, hash, hash_len);
194	if (rc != CKR_OK) {
195		(void) digest_mgr_cleanup(&digest_ctx);
196		return (rc);
197	}
198
199	hash_len = sizeof (hash);
200	rc = digest_mgr_digest_final(sess, &digest_ctx, hash, &hash_len);
201	if (rc != CKR_OK) {
202		(void) digest_mgr_cleanup(&digest_ctx);
203		return (rc);
204	}
205
206	(void) memcpy(out_data, hash, hmac_len);
207	*out_data_len = hmac_len;
208
209	(void) digest_mgr_cleanup(&digest_ctx);
210
211	return (CKR_OK);
212}
213
214CK_RV
215sha1_hmac_verify(SESSION *sess,
216	SIGN_VERIFY_CONTEXT  *ctx,
217	CK_BYTE	*in_data,
218	CK_ULONG in_data_len,
219	CK_BYTE	*signature,
220	CK_ULONG sig_len)
221{
222	CK_BYTE		hmac[SHA1_DIGEST_LENGTH];
223	SIGN_VERIFY_CONTEXT  hmac_ctx;
224	CK_ULONG	hmac_len, len;
225	CK_RV		rc;
226
227	if (! sess || ! ctx || ! in_data || ! signature) {
228		return (CKR_FUNCTION_FAILED);
229	}
230	if (ctx->mech.mechanism == CKM_SHA_1_HMAC_GENERAL)
231		hmac_len = *(CK_ULONG *)ctx->mech.pParameter;
232	else
233		hmac_len = SHA1_DIGEST_LENGTH;
234
235	(void) memset(&hmac_ctx, 0, sizeof (SIGN_VERIFY_CONTEXT));
236
237	rc = sign_mgr_init(sess, &hmac_ctx, &ctx->mech, FALSE, ctx->key);
238	if (rc != CKR_OK) {
239		goto done;
240	}
241	len = sizeof (hmac);
242	rc = sign_mgr_sign(sess, FALSE, &hmac_ctx,
243	    in_data, in_data_len, hmac,   &len);
244	if (rc != CKR_OK) {
245		goto done;
246	}
247	if ((len != hmac_len) || (len != sig_len)) {
248		rc = CKR_SIGNATURE_LEN_RANGE;
249		goto done;
250	}
251
252	if (memcmp(hmac, signature, hmac_len) != 0) {
253		rc = CKR_SIGNATURE_INVALID;
254	}
255	done:
256	(void) sign_mgr_cleanup(&hmac_ctx);
257	return (rc);
258}
259