1N/A/*
1N/A * The Initial Developer of the Original Code is International
1N/A * Business Machines Corporation. Portions created by IBM
1N/A * Corporation are Copyright (C) 2005 International Business
1N/A * Machines Corporation. All Rights Reserved.
1N/A *
1N/A * This program is free software; you can redistribute it and/or modify
1N/A * it under the terms of the Common Public License as published by
1N/A * IBM Corporation; either version 1 of the License, or (at your option)
1N/A * any later version.
1N/A *
1N/A * This program is distributed in the hope that it will be useful,
1N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A * Common Public License for more details.
1N/A *
1N/A * You should have received a copy of the Common Public License
1N/A * along with this program; if not, a copy can be viewed at
1N/A * http://www.opensource.org/licenses/cpl1.0.php.
1N/A */
1N/A
1N/A/* (C) COPYRIGHT International Business Machines Corp. 2001, 2002, 2005 */
1N/A/*
1N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
1N/A * Use is subject to license terms.
1N/A */
1N/A
1N/A#include "tpmtok_int.h"
1N/A
1N/Astatic CK_SLOT_INFO slot_info;
1N/A
1N/A// Function: dlist_add_as_first()
1N/A//
1N/A// Adds the specified node to the start of the list
1N/A//
1N/A// Returns: pointer to the start of the list
1N/A//
1N/ADL_NODE *
1N/Adlist_add_as_first(DL_NODE *list, void *data)
1N/A{
1N/A DL_NODE *node = NULL;
1N/A
1N/A if (! data)
1N/A return (list);
1N/A node = (DL_NODE *)malloc(sizeof (DL_NODE));
1N/A if (! node)
1N/A return (NULL);
1N/A node->data = data;
1N/A node->prev = NULL;
1N/A node->next = list;
1N/A if (list)
1N/A list->prev = node;
1N/A
1N/A return (node);
1N/A}
1N/A
1N/A
1N/A// Function: dlist_add_as_last()
1N/A//
1N/A// Adds the specified node to the end of the list
1N/A//
1N/A// Returns: pointer to the start of the list
1N/A//
1N/ADL_NODE *
1N/Adlist_add_as_last(DL_NODE *list, void *data) {
1N/A DL_NODE *node = NULL;
1N/A
1N/A if (! data)
1N/A return (list);
1N/A node = (DL_NODE *)malloc(sizeof (DL_NODE));
1N/A if (! node)
1N/A return (NULL);
1N/A node->data = data;
1N/A node->next = NULL;
1N/A
1N/A if (! list) {
1N/A node->prev = NULL;
1N/A return (node);
1N/A } else {
1N/A DL_NODE *temp = dlist_get_last(list);
1N/A temp->next = node;
1N/A node->prev = temp;
1N/A
1N/A return (list);
1N/A }
1N/A}
1N/A
1N/A
1N/A// Function: dlist_find()
1N/A//
1N/ADL_NODE *
1N/Adlist_find(DL_NODE *list, void *data)
1N/A{
1N/A DL_NODE *node = list;
1N/A
1N/A while (node && node->data != data)
1N/A node = node->next;
1N/A
1N/A return (node);
1N/A}
1N/A
1N/A
1N/A// Function: dlist_get_first()
1N/A//
1N/A// Returns the last node in the list or NULL if list is empty
1N/A//
1N/ADL_NODE *
1N/Adlist_get_first(DL_NODE *list) {
1N/A DL_NODE *temp = list;
1N/A
1N/A if (! list)
1N/A return (NULL);
1N/A while (temp->prev != NULL)
1N/A temp = temp->prev;
1N/A
1N/A return (temp);
1N/A}
1N/A
1N/A
1N/A// Function: dlist_get_last()
1N/A//
1N/A// Returns the last node in the list or NULL if list is empty
1N/A//
1N/ADL_NODE *
1N/Adlist_get_last(DL_NODE *list) {
1N/A DL_NODE *temp = list;
1N/A
1N/A if (! list)
1N/A return (NULL);
1N/A while (temp->next != NULL)
1N/A temp = temp->next;
1N/A
1N/A return (temp);
1N/A}
1N/A
1N/A
1N/A//
1N/A//
1N/ACK_ULONG
1N/Adlist_length(DL_NODE *list) {
1N/A DL_NODE *temp = list;
1N/A CK_ULONG len = 0;
1N/A
1N/A while (temp) {
1N/A len++;
1N/A temp = temp->next;
1N/A }
1N/A
1N/A return (len);
1N/A}
1N/A
1N/A
1N/A//
1N/A//
1N/ADL_NODE *
1N/Adlist_next(DL_NODE *node)
1N/A{
1N/A if (! node)
1N/A return (NULL);
1N/A return (node->next);
1N/A}
1N/A
1N/A
1N/A//
1N/A//
1N/ADL_NODE *
1N/Adlist_prev(DL_NODE *node) {
1N/A if (! node)
1N/A return (NULL);
1N/A return (node->prev);
1N/A}
1N/A
1N/A
1N/A//
1N/A//
1N/Avoid
1N/Adlist_purge(DL_NODE *list) {
1N/A DL_NODE *node;
1N/A
1N/A if (! list)
1N/A return;
1N/A do {
1N/A node = list->next;
1N/A free(list);
1N/A list = node;
1N/A } while (list);
1N/A}
1N/A
1N/A// Function: dlist_remove_node()
1N/A//
1N/A// Attempts to remove the specified node from the list. The caller is
1N/A// responsible for freeing the data associated with the node prior to
1N/A// calling this routine
1N/A//
1N/ADL_NODE *
1N/Adlist_remove_node(DL_NODE *list, DL_NODE *node) {
1N/A DL_NODE *temp = list;
1N/A
1N/A if (! list || ! node)
1N/A return (NULL);
1N/A // special case: removing head of the list
1N/A //
1N/A if (list == node) {
1N/A temp = list->next;
1N/A if (temp)
1N/A temp->prev = NULL;
1N/A
1N/A free(list);
1N/A return (temp);
1N/A }
1N/A
1N/A // we have no guarantee that the node is in the list
1N/A // so search through the list to find it
1N/A //
1N/A while ((temp != NULL) && (temp->next != node))
1N/A temp = temp->next;
1N/A
1N/A if (temp != NULL) {
1N/A DL_NODE *next = node->next;
1N/A
1N/A temp->next = next;
1N/A if (next)
1N/A next->prev = temp;
1N/A
1N/A free(node);
1N/A }
1N/A
1N/A return (list);
1N/A}
1N/A
1N/Aextern void set_perm(int);
1N/A
1N/Avoid
1N/ACreateXProcLock(void *xproc)
1N/A{
1N/A pthread_mutexattr_t mtxattr;
1N/A
1N/A (void) pthread_mutexattr_init(&mtxattr);
1N/A (void) pthread_mutexattr_setpshared(&mtxattr, PTHREAD_PROCESS_SHARED);
1N/A (void) pthread_mutex_init((pthread_mutex_t *)xproc, &mtxattr);
1N/A}
1N/A
1N/Aint
1N/ADestroyXProcLock(void *xproc)
1N/A{
1N/A return (pthread_mutex_destroy((pthread_mutex_t *)xproc));
1N/A}
1N/A
1N/Aint
1N/AXProcLock(void *xproc)
1N/A{
1N/A return (pthread_mutex_lock((pthread_mutex_t *)xproc));
1N/A}
1N/A
1N/Aint
1N/AXProcUnLock(void *xproc)
1N/A{
1N/A return (pthread_mutex_unlock((pthread_mutex_t *)xproc));
1N/A}
1N/A
1N/A//
1N/A//
1N/A// is_attribute_defined()
1N/A//
1N/A// determine whether the specified attribute is defined by Cryptoki
1N/A//
1N/ACK_BBOOL
1N/Ais_attribute_defined(CK_ATTRIBUTE_TYPE type)
1N/A{
1N/A if (type >= CKA_VENDOR_DEFINED)
1N/A return (TRUE);
1N/A switch (type) {
1N/A case CKA_CLASS:
1N/A case CKA_TOKEN:
1N/A case CKA_PRIVATE:
1N/A case CKA_LABEL:
1N/A case CKA_APPLICATION:
1N/A case CKA_VALUE:
1N/A case CKA_CERTIFICATE_TYPE:
1N/A case CKA_ISSUER:
1N/A case CKA_SERIAL_NUMBER:
1N/A case CKA_KEY_TYPE:
1N/A case CKA_SUBJECT:
1N/A case CKA_ID:
1N/A case CKA_SENSITIVE:
1N/A case CKA_ENCRYPT:
1N/A case CKA_DECRYPT:
1N/A case CKA_WRAP:
1N/A case CKA_UNWRAP:
1N/A case CKA_SIGN:
1N/A case CKA_SIGN_RECOVER:
1N/A case CKA_VERIFY:
1N/A case CKA_VERIFY_RECOVER:
1N/A case CKA_DERIVE:
1N/A case CKA_START_DATE:
1N/A case CKA_END_DATE:
1N/A case CKA_MODULUS:
1N/A case CKA_MODULUS_BITS:
1N/A case CKA_PUBLIC_EXPONENT:
1N/A case CKA_PRIVATE_EXPONENT:
1N/A case CKA_PRIME_1:
1N/A case CKA_PRIME_2:
1N/A case CKA_EXPONENT_1:
1N/A case CKA_EXPONENT_2:
1N/A case CKA_COEFFICIENT:
1N/A case CKA_PRIME:
1N/A case CKA_SUBPRIME:
1N/A case CKA_BASE:
1N/A case CKA_VALUE_BITS:
1N/A case CKA_VALUE_LEN:
1N/A case CKA_EXTRACTABLE:
1N/A case CKA_LOCAL:
1N/A case CKA_NEVER_EXTRACTABLE:
1N/A case CKA_ALWAYS_SENSITIVE:
1N/A case CKA_MODIFIABLE:
1N/A case CKA_ECDSA_PARAMS:
1N/A case CKA_EC_POINT:
1N/A case CKA_HW_FEATURE_TYPE:
1N/A case CKA_HAS_RESET:
1N/A case CKA_RESET_ON_INIT:
1N/A case CKA_KEY_GEN_MECHANISM:
1N/A case CKA_PRIME_BITS:
1N/A case CKA_SUBPRIME_BITS:
1N/A case CKA_OBJECT_ID:
1N/A case CKA_AC_ISSUER:
1N/A case CKA_OWNER:
1N/A case CKA_ATTR_TYPES:
1N/A case CKA_TRUSTED:
1N/A return (TRUE);
1N/A }
1N/A
1N/A return (FALSE);
1N/A}
1N/A
1N/Avoid
1N/Ainit_slot_info(TOKEN_DATA *td)
1N/A{
1N/A /*
1N/A * Much of the token info is pulled from the TPM itself when
1N/A * C_Initialize is called.
1N/A */
1N/A (void) (void) memset(&slot_info.slotDescription, ' ',
1N/A sizeof (slot_info.slotDescription) - 1);
1N/A (void) (void) memset(&slot_info.manufacturerID, ' ',
1N/A sizeof (slot_info.manufacturerID) - 1);
1N/A
1N/A (void) (void) memcpy(&slot_info.slotDescription,
1N/A "PKCS#11 Interface for TPM",
1N/A strlen("PKCS#11 Interface for TPM"));
1N/A
1N/A (void) (void) memcpy(&slot_info.manufacturerID,
1N/A td->token_info.manufacturerID,
1N/A strlen((char *)td->token_info.manufacturerID));
1N/A
1N/A slot_info.hardwareVersion = nv_token_data->token_info.hardwareVersion;
1N/A slot_info.firmwareVersion = nv_token_data->token_info.firmwareVersion;
1N/A slot_info.flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
1N/A}
1N/A
1N/A/*ARGSUSED*/
1N/Avoid
1N/Acopy_slot_info(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR sinfo)
1N/A{
1N/A if (sinfo != NULL)
1N/A (void) memcpy(sinfo, &slot_info, sizeof (slot_info));
1N/A}
1N/A
1N/Astatic void
1N/Ainit_token_info(TOKEN_DATA *td)
1N/A{
1N/A CK_TOKEN_INFO *token_info = NULL;
1N/A
1N/A token_info = &td->token_info;
1N/A
1N/A (void) memset(token_info->model, ' ',
1N/A sizeof (token_info->model));
1N/A (void) memset(token_info->serialNumber, ' ',
1N/A sizeof (token_info->serialNumber));
1N/A
1N/A //
1N/A // I don't see any API support for changing the clock so
1N/A // we will use the system clock for the token's clock.
1N/A //
1N/A token_info->flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_CLOCK_ON_TOKEN |
1N/A CKF_SO_PIN_TO_BE_CHANGED;
1N/A
1N/A if (memcmp(td->user_pin_sha, "00000000000000000000",
1N/A SHA1_DIGEST_LENGTH) != 0)
1N/A token_info->flags |= CKF_USER_PIN_INITIALIZED;
1N/A else
1N/A token_info->flags |= CKF_USER_PIN_TO_BE_CHANGED;
1N/A
1N/A // For the release, we made these
1N/A // values as CK_UNAVAILABLE_INFORMATION
1N/A //
1N/A token_info->ulMaxSessionCount = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulSessionCount = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulMaxRwSessionCount = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulRwSessionCount = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulMaxPinLen = MAX_PIN_LEN;
1N/A token_info->ulMinPinLen = MIN_PIN_LEN;
1N/A token_info->ulTotalPublicMemory = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulFreePublicMemory = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulTotalPrivateMemory = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A token_info->ulFreePrivateMemory = (CK_ULONG)CK_UNAVAILABLE_INFORMATION;
1N/A
1N/A (void) memset(token_info->utcTime, ' ', sizeof (token_info->utcTime));
1N/A}
1N/A
1N/ACK_RV
1N/Ainit_token_data(TSS_HCONTEXT hContext, TOKEN_DATA *td) {
1N/A CK_RV rc;
1N/A
1N/A (void) memset((char *)td, 0, sizeof (nv_token_data));
1N/A //
1N/A // the normal USER pin is not set when the token is initialized
1N/A //
1N/A (void) memcpy(td->user_pin_sha, "00000000000000000000",
1N/A SHA1_DIGEST_LENGTH);
1N/A (void) memcpy(td->so_pin_sha, default_so_pin_sha,
1N/A SHA1_DIGEST_LENGTH);
1N/A
1N/A (void) memset(user_pin_md5, 0x0, MD5_DIGEST_LENGTH);
1N/A (void) memcpy(so_pin_md5, default_so_pin_md5, MD5_DIGEST_LENGTH);
1N/A
1N/A (void) memcpy(td->next_token_object_name, "00000000", 8);
1N/A
1N/A td->tweak_vector.allow_key_mods = TRUE;
1N/A
1N/A init_token_info(td);
1N/A
1N/A rc = token_get_tpm_info(hContext, td);
1N/A if (rc != CKR_OK)
1N/A return (rc);
1N/A
1N/A rc = save_token_data(td);
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/A// Function: compute_next_token_obj_name()
1N/A//
1N/A// Given a token object name (8 bytes in the range [0 - 9A - Z])
1N/A// increment by one adjusting as necessary
1N/A//
1N/A// This gives us a namespace of 36^8 = 2, 821, 109, 907, 456
1N/A// objects before wrapping around.
1N/A//
1N/ACK_RV
1N/Acompute_next_token_obj_name(CK_BYTE *current, CK_BYTE *next) {
1N/A int val[8];
1N/A int i;
1N/A
1N/A if (! current || ! next) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A // Convert to integral base 36
1N/A //
1N/A for (i = 0; i < 8; i++) {
1N/A if (current[i] >= '0' && current[i] <= '9')
1N/A val[i] = current[i] - '0';
1N/A
1N/A if (current[i] >= 'A' && current[i] <= 'Z')
1N/A val[i] = current[i] - 'A' + 10;
1N/A }
1N/A
1N/A val[0]++;
1N/A
1N/A i = 0;
1N/A
1N/A while (val[i] > 35) {
1N/A val[i] = 0;
1N/A
1N/A if (i + 1 < 8) {
1N/A val[i + 1]++;
1N/A i++;
1N/A } else {
1N/A val[0]++;
1N/A i = 0; // start pass 2
1N/A }
1N/A }
1N/A
1N/A // now, convert back to [0 - 9A - Z]
1N/A //
1N/A for (i = 0; i < 8; i++) {
1N/A if (val[i] < 10)
1N/A next[i] = '0' + val[i];
1N/A else
1N/A next[i] = 'A' + val[i] - 10;
1N/A }
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/A
1N/A//
1N/A//
1N/ACK_RV
1N/Abuild_attribute(CK_ATTRIBUTE_TYPE type,
1N/A CK_BYTE *data,
1N/A CK_ULONG data_len,
1N/A CK_ATTRIBUTE **attrib) {
1N/A CK_ATTRIBUTE *attr = NULL;
1N/A
1N/A attr = (CK_ATTRIBUTE *)malloc(sizeof (CK_ATTRIBUTE) + data_len);
1N/A if (! attr) {
1N/A return (CKR_DEVICE_MEMORY);
1N/A }
1N/A attr->type = type;
1N/A attr->ulValueLen = data_len;
1N/A
1N/A if (data_len > 0) {
1N/A attr->pValue = (CK_BYTE *)attr + sizeof (CK_ATTRIBUTE);
1N/A (void) memcpy(attr->pValue, data, data_len);
1N/A }
1N/A else
1N/A attr->pValue = NULL;
1N/A
1N/A *attrib = attr;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Aadd_pkcs_padding(CK_BYTE * ptr,
1N/A UINT32 block_size,
1N/A UINT32 data_len,
1N/A UINT32 total_len)
1N/A{
1N/A UINT32 i, pad_len;
1N/A CK_BYTE pad_value;
1N/A
1N/A pad_len = block_size - (data_len % block_size);
1N/A pad_value = (CK_BYTE)pad_len;
1N/A
1N/A if (data_len + pad_len > total_len) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A for (i = 0; i < pad_len; i++)
1N/A ptr[i] = pad_value;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Astrip_pkcs_padding(
1N/A CK_BYTE *ptr,
1N/A UINT32 total_len,
1N/A UINT32 *data_len)
1N/A{
1N/A CK_BYTE pad_value;
1N/A
1N/A pad_value = ptr[total_len - 1];
1N/A
1N/A /* We have 'pad_value' bytes of 'pad_value' appended to the end */
1N/A *data_len = total_len - pad_value;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Aremove_leading_zeros(CK_ATTRIBUTE *attr)
1N/A{
1N/A CK_BYTE *ptr = NULL;
1N/A CK_ULONG new_len, i;
1N/A
1N/A ptr = attr->pValue;
1N/A
1N/A for (i = 0; i < attr->ulValueLen; i++) {
1N/A if (ptr[i] != 0x0)
1N/A break;
1N/A }
1N/A
1N/A new_len = attr->ulValueLen - i;
1N/A
1N/A (void) memcpy(ptr, ptr + i, new_len);
1N/A attr->ulValueLen = new_len;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Aparity_is_odd(CK_BYTE b) {
1N/A b = ((b >> 4) ^ b) & 0x0f;
1N/A b = ((b >> 2) ^ b) & 0x03;
1N/A b = ((b >> 1) ^ b) & 0x01;
1N/A
1N/A if (b == 1)
1N/A return (TRUE);
1N/A else
1N/A return (FALSE);
1N/A}
1N/A
1N/ACK_RV
1N/Aattach_shm() {
1N/A if (global_shm != NULL)
1N/A return (CKR_OK);
1N/A
1N/A global_shm = (LW_SHM_TYPE *)calloc(1, sizeof (LW_SHM_TYPE));
1N/A if (global_shm == NULL) {
1N/A return (CKR_HOST_MEMORY);
1N/A }
1N/A CreateXProcLock(&global_shm->mutex);
1N/A
1N/A xproclock = (void *)&global_shm->mutex;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Adetach_shm()
1N/A{
1N/A if (global_shm != NULL) {
1N/A free(global_shm);
1N/A global_shm = NULL;
1N/A }
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Acompute_sha(CK_BYTE *data,
1N/A CK_ULONG_32 len,
1N/A CK_BYTE * hash)
1N/A{
1N/A SHA1_CTX ctx;
1N/A
1N/A SHA1Init(&ctx);
1N/A
1N/A SHA1Update(&ctx, data, len);
1N/A
1N/A SHA1Final(hash, &ctx);
1N/A return (CKR_OK);
1N/A}