1 /*
2 * COPYRIGHT (c) International Business Machines Corp. 2001-2017
3 *
4 * This program is provided under the terms of the Common Public License,
5 * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
6 * software constitutes recipient's acceptance of CPL-1.0 terms which can be
7 * found in the file LICENSE file or at
8 * https://opensource.org/licenses/cpl1.0.php
9 */
10
11 // File: dig_mgr.c
12 //
13 // Digest manager routines
14 //
15
16 #include <pthread.h>
17 #include <string.h> // for memcmp() et al
18 #include <stdlib.h>
19
20 #include "pkcs11types.h"
21 #include "defs.h"
22 #include "host_defs.h"
23 #include "h_extern.h"
24 #include "tok_spec_struct.h"
25 #include "trace.h"
26
27
28 //
29 //
digest_mgr_init(STDLL_TokData_t * tokdata,SESSION * sess,DIGEST_CONTEXT * ctx,CK_MECHANISM * mech)30 CK_RV digest_mgr_init(STDLL_TokData_t *tokdata,
31 SESSION *sess, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech)
32 {
33 CK_RV rc = CKR_OK;
34 CK_BYTE *ptr = NULL;
35
36 if (!sess || !ctx) {
37 TRACE_ERROR("Invalid function arguments.\n");
38 return CKR_FUNCTION_FAILED;
39 }
40 if (ctx->active != FALSE) {
41 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
42 return CKR_OPERATION_ACTIVE;
43 }
44 // is the mechanism supported? is the parameter present if required?
45 //
46 switch (mech->mechanism) {
47 case CKM_SHA_1:
48 case CKM_SHA224:
49 case CKM_SHA256:
50 case CKM_SHA384:
51 case CKM_SHA512:
52 case CKM_SHA512_224:
53 case CKM_SHA512_256:
54 if (mech->ulParameterLen != 0) {
55 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
56 return CKR_MECHANISM_PARAM_INVALID;
57 }
58
59 ctx->context = NULL;
60 rc = sha_init(tokdata, sess, ctx, mech);
61 if (rc != CKR_OK) {
62 digest_mgr_cleanup(ctx); // to de-initialize context above
63 TRACE_ERROR("Failed to init sha context.\n");
64 return rc;
65 }
66 break;
67 case CKM_MD2:
68 if (mech->ulParameterLen != 0) {
69 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
70 return CKR_MECHANISM_PARAM_INVALID;
71 }
72 ctx->context_len = sizeof(MD2_CONTEXT);
73 ctx->context = (CK_BYTE *) malloc(sizeof(MD2_CONTEXT));
74 if (!ctx->context) {
75 digest_mgr_cleanup(ctx); // to de-initialize context above
76 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
77 return CKR_HOST_MEMORY;
78 }
79 memset(ctx->context, 0x0, sizeof(MD2_CONTEXT));
80 break;
81 case CKM_MD5:
82 if (mech->ulParameterLen != 0) {
83 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
84 return CKR_MECHANISM_PARAM_INVALID;
85 }
86 ctx->context_len = sizeof(MD5_CONTEXT);
87 ctx->context = (CK_BYTE *) malloc(sizeof(MD5_CONTEXT));
88 if (!ctx->context) {
89 digest_mgr_cleanup(ctx); // to de-initialize context above
90 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
91 return CKR_HOST_MEMORY;
92 }
93 ckm_md5_init(tokdata, (MD5_CONTEXT *) ctx->context);
94 break;
95 default:
96 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
97 return CKR_MECHANISM_INVALID;
98 }
99
100 if (mech->ulParameterLen > 0) {
101 ptr = (CK_BYTE *) malloc(mech->ulParameterLen);
102 if (!ptr) {
103 digest_mgr_cleanup(ctx); // to de-initialize context above
104 TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
105 return CKR_HOST_MEMORY;
106 }
107 memcpy(ptr, mech->pParameter, mech->ulParameterLen);
108 }
109 ctx->mech.ulParameterLen = mech->ulParameterLen;
110 ctx->mech.mechanism = mech->mechanism;
111 ctx->mech.pParameter = ptr;
112 ctx->multi_init = FALSE;
113 ctx->multi = FALSE;
114 ctx->active = TRUE;
115
116 return CKR_OK;
117 }
118
119
120 //
121 //
digest_mgr_cleanup(DIGEST_CONTEXT * ctx)122 CK_RV digest_mgr_cleanup(DIGEST_CONTEXT *ctx)
123 {
124 if (!ctx) {
125 TRACE_ERROR("Invalid function argument.\n");
126 return CKR_FUNCTION_FAILED;
127 }
128 ctx->mech.ulParameterLen = 0;
129 ctx->mech.mechanism = 0;
130 ctx->multi_init = FALSE;
131 ctx->multi = FALSE;
132 ctx->active = FALSE;
133 ctx->context_len = 0;
134
135 if (ctx->mech.pParameter) {
136 free(ctx->mech.pParameter);
137 ctx->mech.pParameter = NULL;
138 }
139
140 if (ctx->context != NULL) {
141 free(ctx->context);
142 ctx->context = NULL;
143 }
144
145 return CKR_OK;
146 }
147
148
149
150 //
151 //
digest_mgr_digest(STDLL_TokData_t * tokdata,SESSION * sess,CK_BBOOL length_only,DIGEST_CONTEXT * ctx,CK_BYTE * in_data,CK_ULONG in_data_len,CK_BYTE * out_data,CK_ULONG * out_data_len)152 CK_RV digest_mgr_digest(STDLL_TokData_t *tokdata,
153 SESSION *sess,
154 CK_BBOOL length_only,
155 DIGEST_CONTEXT *ctx,
156 CK_BYTE *in_data,
157 CK_ULONG in_data_len,
158 CK_BYTE *out_data, CK_ULONG *out_data_len)
159 {
160 CK_RV rc;
161
162 if (!sess || !ctx) {
163 TRACE_ERROR("Invalid function arguments.\n");
164 return CKR_FUNCTION_FAILED;
165 }
166 if (ctx->active == FALSE) {
167 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED));
168 return CKR_OPERATION_NOT_INITIALIZED;
169 }
170 if (ctx->multi_init == FALSE) {
171 ctx->multi = FALSE;
172 ctx->multi_init = TRUE;
173 }
174
175 if (!in_data || !out_data_len) {
176 TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
177 rc = CKR_ARGUMENTS_BAD;
178 goto out;
179 }
180
181 // if the caller just wants the encrypted length, there is no reason to
182 // specify the input data. I just need the data length
183 //
184 if ((length_only == FALSE) && (!in_data || !out_data)) {
185 TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
186 rc = CKR_FUNCTION_FAILED;
187 goto out;
188 }
189
190 if (ctx->multi == TRUE) {
191 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
192 rc = CKR_OPERATION_ACTIVE;
193 goto out;
194 }
195 switch (ctx->mech.mechanism) {
196 case CKM_SHA_1:
197 case CKM_SHA224:
198 case CKM_SHA256:
199 case CKM_SHA384:
200 case CKM_SHA512:
201 case CKM_SHA512_224:
202 case CKM_SHA512_256:
203 rc = sha_hash(tokdata, sess, length_only, ctx, in_data, in_data_len,
204 out_data, out_data_len);
205 break;
206 #if !(NOMD2 )
207 case CKM_MD2:
208 rc = md2_hash(tokdata, sess, length_only, ctx, in_data, in_data_len,
209 out_data, out_data_len);
210 break;
211 #endif
212 case CKM_MD5:
213 rc = md5_hash(tokdata, sess, length_only, ctx, in_data, in_data_len,
214 out_data, out_data_len);
215 break;
216 default:
217 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
218 rc = CKR_MECHANISM_INVALID;
219 }
220
221 out:
222 if (!((rc == CKR_BUFFER_TOO_SMALL) ||
223 (rc == CKR_OK && length_only == TRUE))) {
224 // "A call to C_Digest always terminates the active digest operation
225 // unless it returns CKR_BUFFER_TOO_SMALL or is a successful call (i.e.,
226 // one which returns CKR_OK) to determine the length of the buffer
227 // needed to hold the message digest."
228 digest_mgr_cleanup(ctx);
229 }
230
231 return rc;
232 }
233
234
235 //
236 //
digest_mgr_digest_update(STDLL_TokData_t * tokdata,SESSION * sess,DIGEST_CONTEXT * ctx,CK_BYTE * data,CK_ULONG data_len)237 CK_RV digest_mgr_digest_update(STDLL_TokData_t *tokdata,
238 SESSION *sess,
239 DIGEST_CONTEXT *ctx,
240 CK_BYTE *data, CK_ULONG data_len)
241 {
242 CK_RV rc;
243
244 if (!sess || !ctx) {
245 TRACE_ERROR("Invalid function arguments.\n");
246 return CKR_FUNCTION_FAILED;
247 }
248 if (ctx->active == FALSE) {
249 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED));
250 return CKR_OPERATION_NOT_INITIALIZED;
251 }
252 if (ctx->multi_init == FALSE) {
253 ctx->multi = TRUE;
254 ctx->multi_init = TRUE;
255 }
256 if (ctx->multi == FALSE) {
257 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
258 rc = CKR_OPERATION_ACTIVE;
259 goto out;
260 }
261
262 if (!data && data_len != 0) {
263 TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
264 rc = CKR_ARGUMENTS_BAD;
265 goto out;
266 }
267
268 switch (ctx->mech.mechanism) {
269 case CKM_SHA_1:
270 case CKM_SHA224:
271 case CKM_SHA256:
272 case CKM_SHA384:
273 case CKM_SHA512:
274 case CKM_SHA512_224:
275 case CKM_SHA512_256:
276 rc = sha_hash_update(tokdata, sess, ctx, data, data_len);
277 break;
278 #if !(NOMD2)
279 case CKM_MD2:
280 rc = md2_hash_update(tokdata, sess, ctx, data, data_len);
281 break;
282 #endif
283 case CKM_MD5:
284 rc = md5_hash_update(tokdata, sess, ctx, data, data_len);
285 break;
286 default:
287 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
288 rc = CKR_MECHANISM_INVALID;
289 }
290
291 out:
292 if (rc != CKR_OK) {
293 digest_mgr_cleanup(ctx);
294 // "A call to C_DigestUpdate which results in an error
295 // terminates the current digest operation."
296 }
297
298 return rc;
299 }
300
301
302 //
303 //
digest_mgr_digest_key(STDLL_TokData_t * tokdata,SESSION * sess,DIGEST_CONTEXT * ctx,CK_OBJECT_HANDLE key_handle)304 CK_RV digest_mgr_digest_key(STDLL_TokData_t *tokdata,
305 SESSION *sess,
306 DIGEST_CONTEXT *ctx, CK_OBJECT_HANDLE key_handle)
307 {
308 CK_ATTRIBUTE *attr = NULL;
309 OBJECT *key_obj = NULL;
310 CK_OBJECT_CLASS class;
311 CK_RV rc;
312
313
314 if (!sess || !ctx) {
315 TRACE_ERROR("Invalid function arguments.\n");
316 return CKR_FUNCTION_FAILED;
317 }
318
319 /*
320 * Secure keys can not be digested by digesting the CKA_VALUE attribute.
321 */
322 if (is_secure_key_token()) {
323 TRACE_ERROR("%s because its a secure key token\n",
324 ock_err(CKR_KEY_INDIGESTIBLE));
325 rc = CKR_KEY_INDIGESTIBLE;
326 goto out;
327 }
328
329 rc = object_mgr_find_in_map1(tokdata, key_handle, &key_obj);
330 if (rc != CKR_OK) {
331 TRACE_ERROR("%s\n", ock_err(ERR_KEY_HANDLE_INVALID));
332 rc = CKR_KEY_HANDLE_INVALID;
333 goto out;
334 }
335 // only allow digesting of CKO_SECRET keys
336 //
337 rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr);
338 if (rc == FALSE) {
339 TRACE_ERROR("%s\n", ock_err(ERR_KEY_INDIGESTIBLE));
340 rc = CKR_KEY_INDIGESTIBLE;
341 goto out;
342 } else {
343 class = *(CK_OBJECT_CLASS *) attr->pValue;
344 }
345
346 if (class != CKO_SECRET_KEY) {
347 TRACE_ERROR("%s\n", ock_err(ERR_KEY_INDIGESTIBLE));
348 rc = CKR_KEY_INDIGESTIBLE;
349 goto out;
350 }
351 // every secret key has a CKA_VALUE attribute
352 //
353 rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr);
354 if (!rc) {
355 TRACE_ERROR("%s\n", ock_err(ERR_KEY_INDIGESTIBLE));
356 rc = CKR_KEY_INDIGESTIBLE;
357 goto out;
358 }
359 rc = digest_mgr_digest_update(tokdata, sess, ctx,
360 attr->pValue, attr->ulValueLen);
361 if (rc != CKR_OK) {
362 TRACE_DEVEL("digest_mgr_digest_update failed\n");
363 }
364
365 out:
366 if (rc != CKR_OK) {
367 digest_mgr_cleanup(ctx);
368 }
369
370 return rc;
371 }
372
373
374 //
375 //
digest_mgr_digest_final(STDLL_TokData_t * tokdata,SESSION * sess,CK_BBOOL length_only,DIGEST_CONTEXT * ctx,CK_BYTE * hash,CK_ULONG * hash_len)376 CK_RV digest_mgr_digest_final(STDLL_TokData_t *tokdata,
377 SESSION *sess,
378 CK_BBOOL length_only,
379 DIGEST_CONTEXT *ctx,
380 CK_BYTE *hash, CK_ULONG *hash_len)
381 {
382 CK_RV rc;
383
384 if (!sess || !ctx) {
385 TRACE_ERROR("Invalid function arguments.\n");
386 return CKR_FUNCTION_FAILED;
387 }
388 if (ctx->active == FALSE) {
389 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_NOT_INITIALIZED));
390 return CKR_OPERATION_NOT_INITIALIZED;
391 }
392 if (ctx->multi_init == FALSE) {
393 ctx->multi = TRUE;
394 ctx->multi_init = TRUE;
395 }
396 if (ctx->multi == FALSE) {
397 TRACE_ERROR("%s\n", ock_err(ERR_OPERATION_ACTIVE));
398 rc = CKR_OPERATION_ACTIVE;
399 goto out;
400 }
401
402 if (!hash_len) {
403 TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD));
404 rc = CKR_ARGUMENTS_BAD;
405 goto out;
406 }
407
408 switch (ctx->mech.mechanism) {
409 case CKM_SHA_1:
410 case CKM_SHA224:
411 case CKM_SHA256:
412 case CKM_SHA384:
413 case CKM_SHA512:
414 case CKM_SHA512_224:
415 case CKM_SHA512_256:
416 rc = sha_hash_final(tokdata, sess, length_only, ctx, hash, hash_len);
417 break;
418 #if !(NOMD2)
419 case CKM_MD2:
420 rc = md2_hash_final(tokdata, sess, length_only, ctx, hash, hash_len);
421 break;
422 #endif
423 case CKM_MD5:
424 rc = md5_hash_final(tokdata, sess, length_only, ctx, hash, hash_len);
425 break;
426 default:
427 TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
428 rc = CKR_MECHANISM_INVALID; // shouldn't happen
429 }
430
431 out:
432 if (!((rc == CKR_BUFFER_TOO_SMALL) ||
433 (rc == CKR_OK && length_only == TRUE))) {
434 // "A call to C_DigestFinal always terminates the active digest
435 // operation unless it returns CKR_BUFFER_TOO_SMALL or is a successful
436 // call (i.e., one which returns CKR_OK) to determine the length of the
437 // buffer needed to hold the message digest."
438 digest_mgr_cleanup(ctx);
439 }
440
441 return rc;
442 }
443