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
30static CK_SLOT_INFO    slot_info;
31
32// Function:  dlist_add_as_first()
33//
34// Adds the specified node to the start of the list
35//
36// Returns:  pointer to the start of the list
37//
38DL_NODE *
39dlist_add_as_first(DL_NODE *list, void *data)
40{
41	DL_NODE *node = NULL;
42
43	if (! data)
44		return (list);
45	node = (DL_NODE *)malloc(sizeof (DL_NODE));
46	if (! node)
47		return (NULL);
48	node->data = data;
49	node->prev = NULL;
50	node->next = list;
51	if (list)
52		list->prev = node;
53
54	return (node);
55}
56
57
58// Function:  dlist_add_as_last()
59//
60// Adds the specified node to the end of the list
61//
62// Returns:  pointer to the start of the list
63//
64DL_NODE *
65dlist_add_as_last(DL_NODE *list, void *data) {
66	DL_NODE *node = NULL;
67
68	if (! data)
69		return (list);
70	node = (DL_NODE *)malloc(sizeof (DL_NODE));
71	if (! node)
72		return (NULL);
73	node->data = data;
74	node->next = NULL;
75
76	if (! list) {
77		node->prev = NULL;
78		return (node);
79	} else {
80		DL_NODE *temp = dlist_get_last(list);
81		temp->next = node;
82		node->prev = temp;
83
84		return (list);
85	}
86}
87
88
89// Function:  dlist_find()
90//
91DL_NODE *
92dlist_find(DL_NODE *list, void *data)
93{
94	DL_NODE *node = list;
95
96	while (node && node->data != data)
97	node = node->next;
98
99	return (node);
100}
101
102
103// Function:  dlist_get_first()
104//
105// Returns the last node in the list or NULL if list is empty
106//
107DL_NODE *
108dlist_get_first(DL_NODE *list) {
109	DL_NODE *temp = list;
110
111	if (! list)
112		return (NULL);
113	while (temp->prev != NULL)
114	temp = temp->prev;
115
116	return (temp);
117}
118
119
120// Function:  dlist_get_last()
121//
122// Returns the last node in the list or NULL if list is empty
123//
124DL_NODE *
125dlist_get_last(DL_NODE *list) {
126	DL_NODE *temp = list;
127
128	if (! list)
129		return (NULL);
130	while (temp->next != NULL)
131	temp = temp->next;
132
133	return (temp);
134}
135
136
137//
138//
139CK_ULONG
140dlist_length(DL_NODE *list) {
141	DL_NODE  *temp = list;
142	CK_ULONG  len  = 0;
143
144	while (temp) {
145		len++;
146		temp = temp->next;
147	}
148
149	return (len);
150}
151
152
153//
154//
155DL_NODE *
156dlist_next(DL_NODE *node)
157{
158	if (! node)
159		return (NULL);
160	return (node->next);
161}
162
163
164//
165//
166DL_NODE *
167dlist_prev(DL_NODE *node) {
168	if (! node)
169		return (NULL);
170	return (node->prev);
171}
172
173
174//
175//
176void
177dlist_purge(DL_NODE *list) {
178	DL_NODE *node;
179
180	if (! list)
181		return;
182	do {
183		node = list->next;
184		free(list);
185		list = node;
186	} while (list);
187}
188
189// Function:  dlist_remove_node()
190//
191// Attempts to remove the specified node from the list.  The caller is
192// responsible for freeing the data associated with the node prior to
193// calling this routine
194//
195DL_NODE *
196dlist_remove_node(DL_NODE *list, DL_NODE *node) {
197	DL_NODE *temp  = list;
198
199	if (! list || ! node)
200		return (NULL);
201	// special case:  removing head of the list
202	//
203	if (list == node) {
204		temp = list->next;
205		if (temp)
206			temp->prev = NULL;
207
208		free(list);
209		return (temp);
210	}
211
212	// we have no guarantee that the node is in the list
213	// so search through the list to find it
214	//
215	while ((temp != NULL) && (temp->next != node))
216	temp = temp->next;
217
218	if (temp != NULL) {
219		DL_NODE *next = node->next;
220
221		temp->next = next;
222		if (next)
223			next->prev = temp;
224
225		free(node);
226	}
227
228	return (list);
229}
230
231extern void set_perm(int);
232
233void
234CreateXProcLock(void *xproc)
235{
236	pthread_mutexattr_t  mtxattr;
237
238	(void) pthread_mutexattr_init(&mtxattr);
239	(void) pthread_mutexattr_setpshared(&mtxattr, PTHREAD_PROCESS_SHARED);
240	(void) pthread_mutex_init((pthread_mutex_t *)xproc, &mtxattr);
241}
242
243int
244DestroyXProcLock(void *xproc)
245{
246	return (pthread_mutex_destroy((pthread_mutex_t *)xproc));
247}
248
249int
250XProcLock(void *xproc)
251{
252	return (pthread_mutex_lock((pthread_mutex_t *)xproc));
253}
254
255int
256XProcUnLock(void *xproc)
257{
258	return (pthread_mutex_unlock((pthread_mutex_t *)xproc));
259}
260
261//
262//
263// is_attribute_defined()
264//
265// determine whether the specified attribute is defined by Cryptoki
266//
267CK_BBOOL
268is_attribute_defined(CK_ATTRIBUTE_TYPE type)
269{
270	if (type >= CKA_VENDOR_DEFINED)
271		return (TRUE);
272	switch (type) {
273		case  CKA_CLASS:
274		case  CKA_TOKEN:
275		case  CKA_PRIVATE:
276		case  CKA_LABEL:
277		case  CKA_APPLICATION:
278		case  CKA_VALUE:
279		case  CKA_CERTIFICATE_TYPE:
280		case  CKA_ISSUER:
281		case  CKA_SERIAL_NUMBER:
282		case  CKA_KEY_TYPE:
283		case  CKA_SUBJECT:
284		case  CKA_ID:
285		case  CKA_SENSITIVE:
286		case  CKA_ENCRYPT:
287		case  CKA_DECRYPT:
288		case  CKA_WRAP:
289		case  CKA_UNWRAP:
290		case  CKA_SIGN:
291		case  CKA_SIGN_RECOVER:
292		case  CKA_VERIFY:
293		case  CKA_VERIFY_RECOVER:
294		case  CKA_DERIVE:
295		case  CKA_START_DATE:
296		case  CKA_END_DATE:
297		case  CKA_MODULUS:
298		case  CKA_MODULUS_BITS:
299		case  CKA_PUBLIC_EXPONENT:
300		case  CKA_PRIVATE_EXPONENT:
301		case  CKA_PRIME_1:
302		case  CKA_PRIME_2:
303		case  CKA_EXPONENT_1:
304		case  CKA_EXPONENT_2:
305		case  CKA_COEFFICIENT:
306		case  CKA_PRIME:
307		case  CKA_SUBPRIME:
308		case  CKA_BASE:
309		case  CKA_VALUE_BITS:
310		case  CKA_VALUE_LEN:
311		case  CKA_EXTRACTABLE:
312		case  CKA_LOCAL:
313		case  CKA_NEVER_EXTRACTABLE:
314		case  CKA_ALWAYS_SENSITIVE:
315		case  CKA_MODIFIABLE:
316		case  CKA_ECDSA_PARAMS:
317		case  CKA_EC_POINT:
318		case  CKA_HW_FEATURE_TYPE:
319		case  CKA_HAS_RESET:
320		case  CKA_RESET_ON_INIT:
321		case  CKA_KEY_GEN_MECHANISM:
322		case  CKA_PRIME_BITS:
323		case  CKA_SUBPRIME_BITS:
324		case  CKA_OBJECT_ID:
325		case  CKA_AC_ISSUER:
326		case  CKA_OWNER:
327		case  CKA_ATTR_TYPES:
328		case  CKA_TRUSTED:
329		return (TRUE);
330	}
331
332	return (FALSE);
333}
334
335void
336init_slot_info(TOKEN_DATA *td)
337{
338	/*
339	 * Much of the token info is pulled from the TPM itself when
340	 * C_Initialize is called.
341	 */
342	(void) (void) memset(&slot_info.slotDescription, ' ',
343	    sizeof (slot_info.slotDescription) - 1);
344	(void) (void) memset(&slot_info.manufacturerID,  ' ',
345	    sizeof (slot_info.manufacturerID) - 1);
346
347	(void) (void) memcpy(&slot_info.slotDescription,
348	    "PKCS#11 Interface for TPM",
349	    strlen("PKCS#11 Interface for TPM"));
350
351	(void) (void) memcpy(&slot_info.manufacturerID,
352	    td->token_info.manufacturerID,
353	    strlen((char *)td->token_info.manufacturerID));
354
355	slot_info.hardwareVersion = nv_token_data->token_info.hardwareVersion;
356	slot_info.firmwareVersion = nv_token_data->token_info.firmwareVersion;
357	slot_info.flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
358}
359
360/*ARGSUSED*/
361void
362copy_slot_info(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR sinfo)
363{
364	if (sinfo != NULL)
365		(void) memcpy(sinfo, &slot_info, sizeof (slot_info));
366}
367
368static void
369init_token_info(TOKEN_DATA *td)
370{
371	CK_TOKEN_INFO    *token_info = NULL;
372
373	token_info = &td->token_info;
374
375	(void) memset(token_info->model, ' ',
376	    sizeof (token_info->model));
377	(void) memset(token_info->serialNumber, ' ',
378	    sizeof (token_info->serialNumber));
379
380	//
381	// I don't see any API support for changing the clock so
382	// we will use the system clock for the token's clock.
383	//
384	token_info->flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_CLOCK_ON_TOKEN |
385	    CKF_SO_PIN_TO_BE_CHANGED;
386
387	if (memcmp(td->user_pin_sha, "00000000000000000000",
388	    SHA1_DIGEST_LENGTH) != 0)
389		token_info->flags |= CKF_USER_PIN_INITIALIZED;
390	else
391		token_info->flags |= CKF_USER_PIN_TO_BE_CHANGED;
392
393	// For the release, we made these
394	// values as CK_UNAVAILABLE_INFORMATION
395	//
396	token_info->ulMaxSessionCount    = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
397	token_info->ulSessionCount	= (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
398	token_info->ulMaxRwSessionCount  = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
399	token_info->ulRwSessionCount	= (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
400	token_info->ulMaxPinLen	  = MAX_PIN_LEN;
401	token_info->ulMinPinLen	  = MIN_PIN_LEN;
402	token_info->ulTotalPublicMemory  = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
403	token_info->ulFreePublicMemory   = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
404	token_info->ulTotalPrivateMemory = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
405	token_info->ulFreePrivateMemory  = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
406
407	(void) memset(token_info->utcTime, ' ', sizeof (token_info->utcTime));
408}
409
410CK_RV
411init_token_data(TSS_HCONTEXT hContext, TOKEN_DATA *td) {
412	CK_RV rc;
413
414	(void) memset((char *)td, 0, sizeof (nv_token_data));
415	//
416	// the normal USER pin is not set when the token is initialized
417	//
418	(void) memcpy(td->user_pin_sha, "00000000000000000000",
419	    SHA1_DIGEST_LENGTH);
420	(void) memcpy(td->so_pin_sha, default_so_pin_sha,
421	    SHA1_DIGEST_LENGTH);
422
423	(void) memset(user_pin_md5, 0x0, MD5_DIGEST_LENGTH);
424	(void) memcpy(so_pin_md5, default_so_pin_md5, MD5_DIGEST_LENGTH);
425
426	(void) memcpy(td->next_token_object_name, "00000000", 8);
427
428	td->tweak_vector.allow_key_mods   = TRUE;
429
430	init_token_info(td);
431
432	rc = token_get_tpm_info(hContext, td);
433	if (rc != CKR_OK)
434		return (rc);
435
436	rc = save_token_data(td);
437
438	return (rc);
439}
440
441// Function:  compute_next_token_obj_name()
442//
443// Given a token object name (8 bytes in the range [0 - 9A - Z])
444// increment by one adjusting as necessary
445//
446// This gives us a namespace of 36^8 = 2, 821, 109, 907, 456
447// objects before wrapping around.
448//
449CK_RV
450compute_next_token_obj_name(CK_BYTE *current, CK_BYTE *next) {
451	int val[8];
452	int i;
453
454	if (! current || ! next) {
455		return (CKR_FUNCTION_FAILED);
456	}
457	// Convert to integral base 36
458	//
459	for (i = 0; i < 8; i++) {
460		if (current[i] >= '0' && current[i] <= '9')
461			val[i] = current[i] - '0';
462
463		if (current[i] >= 'A' && current[i] <= 'Z')
464			val[i] = current[i] - 'A' + 10;
465	}
466
467	val[0]++;
468
469	i = 0;
470
471	while (val[i] > 35) {
472		val[i] = 0;
473
474		if (i + 1 < 8) {
475			val[i + 1]++;
476			i++;
477		} else {
478			val[0]++;
479			i = 0;   // start pass 2
480		}
481	}
482
483	// now, convert back to [0 - 9A - Z]
484	//
485	for (i = 0; i < 8; i++) {
486		if (val[i] < 10)
487			next[i] = '0' + val[i];
488		else
489			next[i] = 'A' + val[i] - 10;
490	}
491
492	return (CKR_OK);
493}
494
495
496//
497//
498CK_RV
499build_attribute(CK_ATTRIBUTE_TYPE  type,
500	CK_BYTE	   *data,
501	CK_ULONG	   data_len,
502	CK_ATTRIBUTE	**attrib) {
503	CK_ATTRIBUTE *attr = NULL;
504
505	attr = (CK_ATTRIBUTE *)malloc(sizeof (CK_ATTRIBUTE) + data_len);
506	if (! attr) {
507		return (CKR_DEVICE_MEMORY);
508	}
509	attr->type  = type;
510	attr->ulValueLen = data_len;
511
512	if (data_len > 0) {
513		attr->pValue = (CK_BYTE *)attr + sizeof (CK_ATTRIBUTE);
514		(void) memcpy(attr->pValue, data, data_len);
515	}
516	else
517		attr->pValue = NULL;
518
519	 *attrib = attr;
520
521	return (CKR_OK);
522}
523
524CK_RV
525add_pkcs_padding(CK_BYTE  * ptr,
526	UINT32   block_size,
527	UINT32   data_len,
528	UINT32   total_len)
529{
530	UINT32 i, pad_len;
531	CK_BYTE  pad_value;
532
533	pad_len = block_size - (data_len % block_size);
534	pad_value = (CK_BYTE)pad_len;
535
536	if (data_len + pad_len > total_len) {
537		return (CKR_FUNCTION_FAILED);
538	}
539	for (i = 0; i < pad_len; i++)
540		ptr[i] = pad_value;
541
542	return (CKR_OK);
543}
544
545CK_RV
546strip_pkcs_padding(
547	CK_BYTE *ptr,
548	UINT32  total_len,
549	UINT32  *data_len)
550{
551	CK_BYTE  pad_value;
552
553	pad_value = ptr[total_len - 1];
554
555	/* We have 'pad_value' bytes of 'pad_value' appended to the end */
556	*data_len = total_len - pad_value;
557
558	return (CKR_OK);
559}
560
561CK_RV
562remove_leading_zeros(CK_ATTRIBUTE *attr)
563{
564	CK_BYTE   *ptr = NULL;
565	CK_ULONG   new_len, i;
566
567	ptr = attr->pValue;
568
569	for (i = 0; i < attr->ulValueLen; i++) {
570		if (ptr[i] != 0x0)
571			break;
572	}
573
574	new_len = attr->ulValueLen - i;
575
576	(void) memcpy(ptr, ptr + i, new_len);
577	attr->ulValueLen = new_len;
578
579	return (CKR_OK);
580}
581
582CK_RV
583parity_is_odd(CK_BYTE b) {
584	b = ((b >> 4) ^ b) & 0x0f;
585	b = ((b >> 2) ^ b) & 0x03;
586	b = ((b >> 1) ^ b) & 0x01;
587
588	if (b == 1)
589		return (TRUE);
590	else
591		return (FALSE);
592}
593
594CK_RV
595attach_shm() {
596	if (global_shm != NULL)
597		return (CKR_OK);
598
599	global_shm = (LW_SHM_TYPE *)calloc(1, sizeof (LW_SHM_TYPE));
600	if (global_shm == NULL) {
601		return (CKR_HOST_MEMORY);
602	}
603	CreateXProcLock(&global_shm->mutex);
604
605	xproclock = (void *)&global_shm->mutex;
606
607	return (CKR_OK);
608}
609
610CK_RV
611detach_shm()
612{
613	if (global_shm != NULL) {
614		free(global_shm);
615		global_shm = NULL;
616	}
617
618	return (CKR_OK);
619}
620
621CK_RV
622compute_sha(CK_BYTE  *data,
623	CK_ULONG_32   len,
624	CK_BYTE  * hash)
625{
626	SHA1_CTX	ctx;
627
628	SHA1Init(&ctx);
629
630	SHA1Update(&ctx, data, len);
631
632	SHA1Final(hash, &ctx);
633	return (CKR_OK);
634}
635