xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_tpm/common/mech_sha.c (revision 22a84b8d79248a611e4ba663a268d3c4bed054ac)
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 
29 CK_RV
30 sha1_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 
55 CK_RV
56 sha1_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 
214 CK_RV
215 sha1_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