xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_tpm/common/utility.c (revision e5803b76927480e8f9b67b22201c484ccf4c2bcf)
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 
30 static 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 //
38 DL_NODE *
39 dlist_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 //
64 DL_NODE *
65 dlist_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 //
91 DL_NODE *
92 dlist_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 //
107 DL_NODE *
108 dlist_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 //
124 DL_NODE *
125 dlist_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 //
139 CK_ULONG
140 dlist_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 //
155 DL_NODE *
156 dlist_next(DL_NODE *node)
157 {
158 	if (! node)
159 		return (NULL);
160 	return (node->next);
161 }
162 
163 
164 //
165 //
166 DL_NODE *
167 dlist_prev(DL_NODE *node) {
168 	if (! node)
169 		return (NULL);
170 	return (node->prev);
171 }
172 
173 
174 //
175 //
176 void
177 dlist_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 //
195 DL_NODE *
196 dlist_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 
231 extern void set_perm(int);
232 
233 void
234 CreateXProcLock(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 
243 int
244 DestroyXProcLock(void *xproc)
245 {
246 	return (pthread_mutex_destroy((pthread_mutex_t *)xproc));
247 }
248 
249 int
250 XProcLock(void *xproc)
251 {
252 	return (pthread_mutex_lock((pthread_mutex_t *)xproc));
253 }
254 
255 int
256 XProcUnLock(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 //
267 CK_BBOOL
268 is_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 
335 void
336 init_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*/
361 void
362 copy_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 
368 static void
369 init_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 
410 CK_RV
411 init_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 //
449 CK_RV
450 compute_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 //
498 CK_RV
499 build_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 
524 CK_RV
525 add_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 
545 CK_RV
546 strip_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 
561 CK_RV
562 remove_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 
582 CK_RV
583 parity_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 
594 CK_RV
595 attach_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 
610 CK_RV
611 detach_shm()
612 {
613 	if (global_shm != NULL) {
614 		free(global_shm);
615 		global_shm = NULL;
616 	}
617 
618 	return (CKR_OK);
619 }
620 
621 CK_RV
622 compute_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