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