/*
* Common Public License Version 0.5
*
* THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF
* THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE,
* REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
* RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
*
* 1. DEFINITIONS
*
* "Contribution" means:
* a) in the case of the initial Contributor, the
* initial code and documentation distributed under
* this Agreement, and
*
* b) in the case of each subsequent Contributor:
* i) changes to the Program, and
* ii) additions to the Program;
*
* where such changes and/or additions to the Program
* originate from and are distributed by that
* particular Contributor. A Contribution 'originates'
* from a Contributor if it was added to the Program
* by such Contributor itself or anyone acting on such
* Contributor's behalf. Contributions do not include
* additions to the Program which: (i) are separate
* modules of software distributed in conjunction with
* the Program under their own license agreement, and
* (ii) are not derivative works of the Program.
*
*
* "Contributor" means any person or entity that distributes
* the Program.
*
* "Licensed Patents " mean patent claims licensable by a
* Contributor which are necessarily infringed by the use or
* sale of its Contribution alone or when combined with the
* Program.
*
* "Program" means the Contributions distributed in
* accordance with this Agreement.
*
* "Recipient" means anyone who receives the Program under
* this Agreement, including all Contributors.
*
* 2. GRANT OF RIGHTS
*
* a) Subject to the terms of this Agreement, each
* Contributor hereby grants Recipient a
* non-exclusive, worldwide, royalty-free copyright
* license to reproduce, prepare derivative works of,
* publicly display, publicly perform, distribute and
* sublicense the Contribution of such Contributor, if
* any, and such derivative works, in source code and
* object code form.
*
* b) Subject to the terms of this Agreement, each
* Contributor hereby grants Recipient a
* non-exclusive, worldwide, royalty-free patent
* license under Licensed Patents to make, use, sell,
* offer to sell, import and otherwise transfer the
* Contribution of such Contributor, if any, in source
* code and object code form. This patent license
* shall apply to the combination of the Contribution
* and the Program if, at the time the Contribution is
* added by the Contributor, such addition of the
* Contribution causes such combination to be covered
* by the Licensed Patents. The patent license shall
* not apply to any other combinations which include
* the Contribution. No hardware per se is licensed
* hereunder.
*
* c) Recipient understands that although each
* Contributor grants the licenses to its
* Contributions set forth herein, no assurances are
* provided by any Contributor that the Program does
* not infringe the patent or other intellectual
* property rights of any other entity. Each
* Contributor disclaims any liability to Recipient
* for claims brought by any other entity based on
* infringement of intellectual property rights or
* otherwise. As a condition to exercising the rights
* and licenses granted hereunder, each Recipient
* hereby assumes sole responsibility to secure any
* other intellectual property rights needed, if any.
*
* For example, if a third party patent license is
* required to allow Recipient to distribute the
* Program, it is Recipient's responsibility to
* acquire that license before distributing the
* Program.
*
* d) Each Contributor represents that to its
* knowledge it has sufficient copyright rights in its
* Contribution, if any, to grant the copyright
* license set forth in this Agreement.
*
* 3. REQUIREMENTS
*
* A Contributor may choose to distribute the Program in
* object code form under its own license agreement, provided
* that:
* a) it complies with the terms and conditions of
* this Agreement; and
*
* b) its license agreement:
* i) effectively disclaims on behalf of all
* Contributors all warranties and conditions, express
* and implied, including warranties or conditions of
* title and non-infringement, and implied warranties
* or conditions of merchantability and fitness for a
* particular purpose;
*
* ii) effectively excludes on behalf of all
* Contributors all liability for damages, including
* direct, indirect, special, incidental and
* consequential damages, such as lost profits;
*
* iii) states that any provisions which differ from
* this Agreement are offered by that Contributor
* alone and not by any other party; and
*
* iv) states that source code for the Program is
* available from such Contributor, and informs
* licensees how to obtain it in a reasonable manner
* on or through a medium customarily used for
* software exchange.
*
* When the Program is made available in source code form:
* a) it must be made available under this Agreement;
* and
* b) a copy of this Agreement must be included with
* each copy of the Program.
*
* Contributors may not remove or alter any copyright notices
* contained within the Program.
*
* Each Contributor must identify itself as the originator of
* its Contribution, if any, in a manner that reasonably
* allows subsequent Recipients to identify the originator of
* the Contribution.
*
*
* 4. COMMERCIAL DISTRIBUTION
*
* Commercial distributors of software may accept certain
* responsibilities with respect to end users, business
* partners and the like. While this license is intended to
* facilitate the commercial use of the Program, the
* Contributor who includes the Program in a commercial
* product offering should do so in a manner which does not
* create potential liability for other Contributors.
* Therefore, if a Contributor includes the Program in a
* commercial product offering, such Contributor ("Commercial
* Contributor") hereby agrees to defend and indemnify every
* other Contributor ("Indemnified Contributor") against any
* losses, damages and costs (collectively "Losses") arising
* from claims, lawsuits and other legal actions brought by a
* third party against the Indemnified Contributor to the
* extent caused by the acts or omissions of such Commercial
* Contributor in connection with its distribution of the
* Program in a commercial product offering. The obligations
* in this section do not apply to any claims or Losses
* relating to any actual or alleged intellectual property
* infringement. In order to qualify, an Indemnified
* Contributor must: a) promptly notify the Commercial
* Contributor in writing of such claim, and b) allow the
* Commercial Contributor to control, and cooperate with the
* Commercial Contributor in, the defense and any related
* settlement negotiations. The Indemnified Contributor may
* participate in any such claim at its own expense.
*
*
* For example, a Contributor might include the Program in a
* commercial product offering, Product X. That Contributor
* is then a Commercial Contributor. If that Commercial
* Contributor then makes performance claims, or offers
* warranties related to Product X, those performance claims
* and warranties are such Commercial Contributor's
* responsibility alone. Under this section, the Commercial
* Contributor would have to defend claims against the other
* Contributors related to those performance claims and
* warranties, and if a court requires any other Contributor
* to pay any damages as a result, the Commercial Contributor
* must pay those damages.
*
*
* 5. NO WARRANTY
*
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE
* PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
* IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
* CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
* responsible for determining the appropriateness of using
* and distributing the Program and assumes all risks
* associated with its exercise of rights under this
* Agreement, including but not limited to the risks and
* costs of program errors, compliance with applicable laws,
* damage to or loss of data, programs or equipment, and
* unavailability or interruption of operations.
*
* 6. DISCLAIMER OF LIABILITY
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER
* RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
* LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE
* OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* 7. GENERAL
*
* If any provision of this Agreement is invalid or
* unenforceable under applicable law, it shall not affect
* the validity or enforceability of the remainder of the
* terms of this Agreement, and without further action by the
* parties hereto, such provision shall be reformed to the
* minimum extent necessary to make such provision valid and
* enforceable.
*
*
* If Recipient institutes patent litigation against a
* Contributor with respect to a patent applicable to
* software (including a cross-claim or counterclaim in a
* lawsuit), then any patent licenses granted by that
* Contributor to such Recipient under this Agreement shall
* terminate as of the date such litigation is filed. In
* addition, If Recipient institutes patent litigation
* against any entity (including a cross-claim or
* counterclaim in a lawsuit) alleging that the Program
* itself (excluding combinations of the Program with other
* software or hardware) infringes such Recipient's
* patent(s), then such Recipient's rights granted under
* Section 2(b) shall terminate as of the date such
* litigation is filed.
*
* All Recipient's rights under this Agreement shall
* terminate if it fails to comply with any of the material
* terms or conditions of this Agreement and does not cure
* such failure in a reasonable period of time after becoming
* aware of such noncompliance. If all Recipient's rights
* under this Agreement terminate, Recipient agrees to cease
* use and distribution of the Program as soon as reasonably
* practicable. However, Recipient's obligations under this
* Agreement and any licenses granted by Recipient relating
* to the Program shall continue and survive.
*
* Everyone is permitted to copy and distribute copies of
* this Agreement, but in order to avoid inconsistency the
* Agreement is copyrighted and may only be modified in the
* following manner. The Agreement Steward reserves the right
* to publish new versions (including revisions) of this
* Agreement from time to time. No one other than the
* Agreement Steward has the right to modify this Agreement.
*
* IBM is the initial Agreement Steward. IBM may assign the
* responsibility to serve as the Agreement Steward to a
* suitable separate entity. Each new version of the
* Agreement will be given a distinguishing version number.
* The Program (including Contributions) may always be
* distributed subject to the version of the Agreement under
* which it was received. In addition, after a new version of
* the Agreement is published, Contributor may elect to
* distribute the Program (including its Contributions) under
* the new version. Except as expressly stated in Sections
* 2(a) and 2(b) above, Recipient receives no rights or
* licenses to the intellectual property of any Contributor
* under this Agreement, whether expressly, by implication,
* estoppel or otherwise. All rights in the Program not
* expressly granted under this Agreement are reserved.
*
*
* This Agreement is governed by the laws of the State of New
* York and the intellectual property laws of the United
* States of America. No party to this Agreement will bring a
* legal action under this Agreement more than one year after
* the cause of action arose. Each party waives its rights to
* a jury trial in any resulting litigation.
*
*
*
* (C) COPYRIGHT International Business Machines Corp. 2001,2002
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "tpmtok_int.h"
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#define ALTERNATE_KEYSTORE_PATH "PKCS11_TPM_DIR"
#define PWD_BUFFER_SIZE 1024
static char keystore_path[MAXPATHLEN];
static boolean_t keystore_path_initialized = 0;
TSS_HKEY hPrivateLeafKey;
static CK_RV
restore_private_token_object(TSS_HCONTEXT, CK_BYTE *, CK_ULONG, OBJECT *);
static struct flock fl = {
0,
0,
0,
0,
0,
0,
{0, 0, 0, 0}
};
static int
lockfile(int fd, int op)
{
fl.l_type = op;
return (fcntl(fd, F_SETLKW, &fl));
}
static char *
get_user_default_path(char *home_path)
{
struct passwd pwd, *user_info;
char pwdbuf[PWD_BUFFER_SIZE];
if (getpwuid_r(getuid(), &pwd, pwdbuf, PWD_BUFFER_SIZE,
&user_info) != 0)
return (NULL);
(void) snprintf(home_path, MAXPATHLEN, "/var/tpm/pkcs11/%s",
user_info ? user_info->pw_name : "");
return (home_path);
}
char *
get_tpm_keystore_path()
{
char *env_val;
char home_path[MAXPATHLEN];
if (!keystore_path_initialized) {
env_val = getenv(ALTERNATE_KEYSTORE_PATH);
bzero(keystore_path, sizeof (keystore_path));
/*
* If it isn't set or is set to the empty string use the
* default location. We need to check for the empty string
* because some users "unset" environment variables by giving
* them no value, this isn't the same thing as removing it
* from the environment.
*
* We don't want that to attempt to open the token area.
*/
if ((env_val == NULL) || (strcmp(env_val, "") == 0)) {
/* alternate path not specified, use default dir */
char *p = get_user_default_path(home_path);
if (p == NULL)
return (NULL);
(void) snprintf(keystore_path, MAXPATHLEN, "%s", p);
} else {
(void) snprintf(keystore_path, MAXPATHLEN, "%s",
env_val);
}
keystore_path_initialized = 1;
}
return (keystore_path);
}
static CK_RV
create_keystore_dir()
{
char *ksdir = get_tpm_keystore_path();
char objdir[MAXPATHLEN];
CK_RV rv = 0;
if (ksdir == NULL)
return (CKR_FUNCTION_FAILED);
if (mkdir(ksdir, S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
if (errno == EEXIST) {
rv = 0;
} else {
return (CKR_FUNCTION_FAILED);
}
}
if (rv == 0) {
(void) snprintf(objdir, sizeof (objdir),
"%s/%s", ksdir, TOKEN_OBJ_DIR);
if (mkdir(objdir, S_IRUSR|S_IWUSR|S_IXUSR) < 0) {
if (errno == EEXIST) {
rv = 0;
} else {
return (CKR_FUNCTION_FAILED);
}
}
}
return (CKR_OK);
}
static void
set_perm(int file)
{
/*
* In the TPM token, with per user data stores, we don't share the token
* object amongst a group. In fact, we want to restrict access to
* a single user.
*/
(void) fchmod(file, S_IRUSR|S_IWUSR);
}
#define READ_TOKEN_INFO_STR(fp, rec, reclen) rc = fread(rec, reclen, 1, fp); \
if (rc != 1) { rc = CKR_FUNCTION_FAILED; goto out_unlock; }
#define READ_TOKEN_INFO_UINT32(fp, rec) rc = fread(&fieldval, \
sizeof (UINT32), 1, fp); \
if (rc != 1) { rc = CKR_FUNCTION_FAILED; goto out_unlock; } \
rec = (CK_ULONG)fieldval;
CK_RV
load_token_data(TSS_HCONTEXT hContext, TOKEN_DATA *td)
{
FILE *fp;
CK_BYTE fname[MAXPATHLEN];
CK_RV rc;
UINT32 fieldval;
char *p = get_tpm_keystore_path();
if (p == NULL)
return (CKR_FUNCTION_FAILED);
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s", p, TOKEN_DATA_FILE);
rc = XProcLock(xproclock);
if (rc != CKR_OK)
return (rc);
fp = fopen((char *)fname, "r");
if (!fp) {
/* Better error checking added */
if (errno == ENOENT) {
(void) XProcUnLock(xproclock);
rc = create_keystore_dir();
if (rc != 0)
goto out_nolock;
rc = init_token_data(hContext, td);
if (rc != CKR_OK) {
goto out_nolock;
}
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto out_nolock;
}
fp = fopen((char *)fname, "r");
if (!fp) {
LogError("failed opening %s for read: %s",
fname, (char *)strerror(errno));
rc = CKR_FUNCTION_FAILED;
goto out_unlock;
}
} else {
/* Could not open file for some unknown reason */
rc = CKR_FUNCTION_FAILED;
goto out_unlock;
}
}
if (lockfile(fileno(fp), F_RDLCK)) {
(void) fclose(fp);
rc = CKR_FUNCTION_FAILED;
goto out_unlock;
}
set_perm(fileno(fp));
/* Read fields individually because of 64-bit size diffs */
READ_TOKEN_INFO_STR(fp, td->token_info.label,
sizeof (td->token_info.label));
READ_TOKEN_INFO_STR(fp, td->token_info.manufacturerID,
sizeof (td->token_info.manufacturerID));
READ_TOKEN_INFO_STR(fp, td->token_info.model,
sizeof (td->token_info.model));
READ_TOKEN_INFO_STR(fp, td->token_info.serialNumber,
sizeof (td->token_info.serialNumber));
READ_TOKEN_INFO_UINT32(fp, td->token_info.flags);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulMaxSessionCount);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulSessionCount);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulRwSessionCount);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulMaxPinLen);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulMinPinLen);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulTotalPublicMemory);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulFreePublicMemory);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulTotalPrivateMemory);
READ_TOKEN_INFO_UINT32(fp, td->token_info.ulFreePrivateMemory);
READ_TOKEN_INFO_STR(fp, &td->token_info.hardwareVersion,
sizeof (td->token_info.hardwareVersion));
READ_TOKEN_INFO_STR(fp, &td->token_info.firmwareVersion,
sizeof (td->token_info.firmwareVersion));
READ_TOKEN_INFO_STR(fp, td->token_info.utcTime,
sizeof (td->token_info.utcTime));
READ_TOKEN_INFO_STR(fp, td->user_pin_sha,
sizeof (td->user_pin_sha));
READ_TOKEN_INFO_STR(fp, td->so_pin_sha,
sizeof (td->so_pin_sha));
READ_TOKEN_INFO_STR(fp, td->next_token_object_name,
sizeof (td->next_token_object_name));
READ_TOKEN_INFO_STR(fp, &td->tweak_vector,
sizeof (td->tweak_vector));
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
if (rc == 0)
rc = CKR_FUNCTION_FAILED;
else
rc = CKR_OK;
out_unlock:
(void) XProcUnLock(xproclock);
out_nolock:
return (rc);
}
#define WRITE_TOKEN_INFO_STR(fp, rec, reclen) rc = fwrite(rec, reclen, 1, fp); \
if (rc != 1) { rc = CKR_FUNCTION_FAILED; goto done; }
#define WRITE_TOKEN_INFO_UINT32(fp, rec) fieldval = (UINT32)rec; \
rc = fwrite(&fieldval, sizeof (UINT32), 1, fp); \
if (rc != 1) { rc = CKR_FUNCTION_FAILED; goto done; }
CK_RV
save_token_data(TOKEN_DATA *td)
{
FILE *fp;
CK_RV rc;
CK_BYTE fname[MAXPATHLEN];
char *p = get_tpm_keystore_path();
UINT32 fieldval;
if (p == NULL)
return (CKR_FUNCTION_FAILED);
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s", p, TOKEN_DATA_FILE);
rc = XProcLock(xproclock);
if (rc != CKR_OK)
goto out_nolock;
fp = fopen((char *)fname, "w");
if (!fp) {
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (lockfile(fileno(fp), F_WRLCK)) {
rc = CKR_FUNCTION_FAILED;
(void) fclose(fp);
goto done;
}
set_perm(fileno(fp));
/* Write token fields individually to maintain sizes on 64 and 32 bit */
WRITE_TOKEN_INFO_STR(fp, td->token_info.label,
sizeof (td->token_info.label));
WRITE_TOKEN_INFO_STR(fp, td->token_info.manufacturerID,
sizeof (td->token_info.manufacturerID));
WRITE_TOKEN_INFO_STR(fp, td->token_info.model,
sizeof (td->token_info.model));
WRITE_TOKEN_INFO_STR(fp, td->token_info.serialNumber,
sizeof (td->token_info.serialNumber));
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.flags);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulMaxSessionCount);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulSessionCount);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulRwSessionCount);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulMaxPinLen);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulMinPinLen);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulTotalPublicMemory);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulFreePublicMemory);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulTotalPrivateMemory);
WRITE_TOKEN_INFO_UINT32(fp, td->token_info.ulFreePrivateMemory);
WRITE_TOKEN_INFO_STR(fp, &td->token_info.hardwareVersion,
sizeof (td->token_info.hardwareVersion));
WRITE_TOKEN_INFO_STR(fp, &td->token_info.firmwareVersion,
sizeof (td->token_info.firmwareVersion));
WRITE_TOKEN_INFO_STR(fp, td->token_info.utcTime,
sizeof (td->token_info.utcTime));
WRITE_TOKEN_INFO_STR(fp, td->user_pin_sha,
sizeof (td->user_pin_sha));
WRITE_TOKEN_INFO_STR(fp, td->so_pin_sha,
sizeof (td->so_pin_sha));
WRITE_TOKEN_INFO_STR(fp, td->next_token_object_name,
sizeof (td->next_token_object_name));
WRITE_TOKEN_INFO_STR(fp, &td->tweak_vector,
sizeof (td->tweak_vector));
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
rc = CKR_OK;
done:
(void) XProcUnLock(xproclock);
out_nolock:
return (rc);
}
CK_RV
save_token_object(TSS_HCONTEXT hContext, OBJECT *obj)
{
FILE *fp = NULL;
CK_BYTE line[100];
CK_RV rc;
CK_BYTE fname[MAXPATHLEN];
char *p = get_tpm_keystore_path();
if (p == NULL)
return (CKR_FUNCTION_FAILED);
if (object_is_private(obj) == TRUE)
rc = save_private_token_object(hContext, obj);
else
rc = save_public_token_object(obj);
if (rc != CKR_OK)
return (rc);
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s/%s", p, TOKEN_OBJ_DIR, TOKEN_OBJ_INDEX_FILE);
fp = fopen((char *)fname, "r");
if (fp) {
if (lockfile(fileno(fp), F_RDLCK)) {
(void) fclose(fp);
return (CKR_FUNCTION_FAILED);
}
set_perm(fileno(fp));
while (!feof(fp)) {
(void) fgets((char *)line, 50, fp);
if (!feof(fp)) {
line[strlen((char *)line) - 1] = 0;
if (strcmp((char *)line,
(char *)(obj->name)) == 0) {
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
return (CKR_OK);
}
}
}
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
}
fp = fopen((char *)fname, "a");
if (!fp)
return (CKR_FUNCTION_FAILED);
if (lockfile(fileno(fp), F_WRLCK)) {
(void) fclose(fp);
return (CKR_FUNCTION_FAILED);
}
set_perm(fileno(fp));
(void) fprintf(fp, "%s\n", obj->name);
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
return (CKR_OK);
}
CK_RV
save_public_token_object(OBJECT *obj)
{
FILE *fp = NULL;
CK_BYTE *cleartxt = NULL;
CK_BYTE fname[MAXPATHLEN];
UINT32 cleartxt_len;
CK_BBOOL flag = FALSE;
CK_RV rc;
UINT32 total_len;
char *p = get_tpm_keystore_path();
if (p == NULL)
return (CKR_FUNCTION_FAILED);
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s/%s", p, TOKEN_OBJ_DIR, obj->name);
rc = object_flatten(obj, &cleartxt, &cleartxt_len);
if (rc != CKR_OK)
goto error;
fp = fopen((char *)fname, "w");
if (!fp) {
LogError("Error opening %s - %s", fname,
(char *)strerror(errno));
rc = CKR_FUNCTION_FAILED;
goto error;
}
if (lockfile(fileno(fp), F_WRLCK)) {
(void) fclose(fp);
return (CKR_FUNCTION_FAILED);
}
set_perm(fileno(fp));
total_len = cleartxt_len + sizeof (UINT32) + sizeof (CK_BBOOL);
(void) fwrite(&total_len, sizeof (total_len), 1, fp);
(void) fwrite(&flag, sizeof (flag), 1, fp);
(void) fwrite(cleartxt, cleartxt_len, 1, fp);
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
free(cleartxt);
return (CKR_OK);
error:
if (fp)
(void) fclose(fp);
if (cleartxt)
free(cleartxt);
return (rc);
}
CK_RV
save_private_token_object(TSS_HCONTEXT hContext, OBJECT *obj)
{
FILE *fp = NULL;
CK_BYTE *obj_data = NULL;
CK_BYTE *cleartxt = NULL;
CK_BYTE *ciphertxt = NULL;
CK_BYTE *ptr = NULL;
CK_BYTE fname[100];
CK_BYTE hash_sha[SHA1_DIGEST_LENGTH];
CK_BBOOL flag;
CK_RV rc;
CK_ULONG ciphertxt_len;
UINT32 cleartxt_len;
UINT32 padded_len;
UINT32 obj_data_len_32;
UINT32 total_len;
UINT32 chunksize, blocks;
char *p = get_tpm_keystore_path();
if (p == NULL)
return (CKR_FUNCTION_FAILED);
rc = object_flatten(obj, &obj_data, &obj_data_len_32);
if (rc != CKR_OK) {
goto error;
}
/*
* format for the object file:
* private flag
* ---- begin encrypted part <--+
* length of object data (4 bytes) |
* object data +---- sensitive part
* SHA of (object data) |
* ---- end encrypted part <--+
*/
if ((rc = compute_sha(obj_data, obj_data_len_32, hash_sha)) != CKR_OK)
goto error;
/*
* RSA OAEP crypto uses chunks smaller than the max to make room
* for the hashes.
* chunksize = RSA_Modulus_Size - (2 * SHA1_DIGEST_SIZE + 2) - (4 - 1)
* == 209
*/
chunksize = RSA_BLOCK_SIZE - (2 * SHA1_DIGEST_LENGTH + 2) - 5;
cleartxt_len = sizeof (UINT32) + obj_data_len_32 + SHA1_DIGEST_LENGTH;
blocks = cleartxt_len / chunksize + ((cleartxt_len % chunksize) > 0);
padded_len = RSA_BLOCK_SIZE * blocks;
cleartxt = (CK_BYTE *)malloc(padded_len);
ciphertxt = (CK_BYTE *)malloc(padded_len);
if (!cleartxt || !ciphertxt) {
rc = CKR_HOST_MEMORY;
goto error;
}
ciphertxt_len = padded_len;
ptr = cleartxt;
(void) memcpy(ptr, &obj_data_len_32, sizeof (UINT32));
ptr += sizeof (UINT32);
(void) memcpy(ptr, obj_data, obj_data_len_32);
ptr += obj_data_len_32;
(void) memcpy(ptr, hash_sha, SHA1_DIGEST_LENGTH);
(void) add_pkcs_padding(cleartxt + cleartxt_len, RSA_BLOCK_SIZE,
cleartxt_len, padded_len);
/* the encrypt function will compute the padded length */
rc = tpm_encrypt_data(hContext, hPrivateLeafKey, cleartxt, cleartxt_len,
ciphertxt, &ciphertxt_len);
if (rc != CKR_OK) {
goto error;
}
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s/%s", p, TOKEN_OBJ_DIR, obj->name);
fp = fopen((char *)fname, "w");
if (!fp) {
rc = CKR_FUNCTION_FAILED;
goto error;
}
if (lockfile(fileno(fp), F_WRLCK)) {
rc = CKR_FUNCTION_FAILED;
goto error;
}
set_perm(fileno(fp));
total_len = sizeof (UINT32) + sizeof (CK_BBOOL) + (UINT32)ciphertxt_len;
flag = TRUE;
(void) fwrite(&total_len, sizeof (UINT32), 1, fp);
(void) fwrite(&flag, sizeof (CK_BBOOL), 1, fp);
(void) fwrite(ciphertxt, ciphertxt_len, 1, fp);
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
free(obj_data);
free(cleartxt);
free(ciphertxt);
return (CKR_OK);
error:
if (fp)
(void) fclose(fp);
if (obj_data)
free(obj_data);
if (cleartxt)
free(cleartxt);
if (ciphertxt)
free(ciphertxt);
return (rc);
}
CK_RV
load_public_token_objects(void)
{
FILE *fp1 = NULL, *fp2 = NULL;
CK_BYTE *buf = NULL;
CK_BYTE tmp[MAXPATHLEN], fname[MAXPATHLEN], iname[MAXPATHLEN];
CK_BBOOL priv;
UINT32 size;
char *ksdir = get_tpm_keystore_path();
if (ksdir == NULL)
return (CKR_FUNCTION_FAILED);
(void) snprintf((char *)iname, sizeof (iname),
"%s/%s/%s", ksdir,
TOKEN_OBJ_DIR, TOKEN_OBJ_INDEX_FILE);
fp1 = fopen((char *)iname, "r");
if (!fp1)
return (CKR_OK); // no token objects
if (lockfile(fileno(fp1), F_RDLCK)) {
(void) fclose(fp1);
return (CKR_FUNCTION_FAILED);
}
while (!feof(fp1)) {
(void) fgets((char *)tmp, 50, fp1);
if (feof(fp1))
break;
tmp[strlen((char *)tmp) - 1] = 0;
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s/", ksdir, TOKEN_OBJ_DIR);
(void) strncat((char *)fname, (const char *)tmp,
(size_t)sizeof (fname));
fp2 = fopen((char *)fname, "r");
if (!fp2)
continue;
(void) fread(&size, sizeof (UINT32), 1, fp2);
(void) fread(&priv, sizeof (CK_BBOOL), 1, fp2);
if (priv == TRUE) {
(void) fclose(fp2);
continue;
}
size = size - sizeof (UINT32) - sizeof (CK_BBOOL);
buf = (CK_BYTE *)malloc(size);
if (!buf) {
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
(void) fclose(fp2);
return (CKR_HOST_MEMORY);
}
(void) fread(buf, size, 1, fp2);
if (pthread_mutex_lock(&obj_list_mutex)) {
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
(void) fclose(fp2);
free(buf);
return (CKR_FUNCTION_FAILED);
}
(void) object_mgr_restore_obj(buf, NULL);
(void) pthread_mutex_unlock(&obj_list_mutex);
free(buf);
(void) fclose(fp2);
}
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
return (CKR_OK);
}
CK_RV
load_private_token_objects(TSS_HCONTEXT hContext)
{
FILE *fp1 = NULL, *fp2 = NULL;
CK_BYTE *buf = NULL;
CK_BYTE tmp[MAXPATHLEN], fname[MAXPATHLEN], iname[MAXPATHLEN];
CK_BBOOL priv;
UINT32 size;
CK_RV rc;
char *ksdir = get_tpm_keystore_path();
if (ksdir == NULL)
return (CKR_FUNCTION_FAILED);
(void) snprintf((char *)iname, sizeof (iname),
"%s/%s/%s", ksdir, TOKEN_OBJ_DIR, TOKEN_OBJ_INDEX_FILE);
fp1 = fopen((char *)iname, "r");
if (!fp1)
return (CKR_OK);
if (lockfile(fileno(fp1), F_RDLCK)) {
rc = CKR_FUNCTION_FAILED;
goto error;
}
while (!feof(fp1)) {
(void) fgets((char *)tmp, sizeof (tmp), fp1);
if (feof(fp1))
break;
tmp[strlen((char *)tmp) - 1] = 0;
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s/%s", ksdir, TOKEN_OBJ_DIR, tmp);
fp2 = fopen((char *)fname, "r");
if (!fp2)
continue;
(void) fread(&size, sizeof (UINT32), 1, fp2);
(void) fread(&priv, sizeof (CK_BBOOL), 1, fp2);
if (priv == FALSE) {
(void) fclose(fp2);
continue;
}
size = size - sizeof (UINT32) - sizeof (CK_BBOOL);
buf = (CK_BYTE *)malloc(size);
if (!buf) {
rc = CKR_HOST_MEMORY;
goto error;
}
rc = fread((char *)buf, size, 1, fp2);
if (rc != 1) {
rc = CKR_FUNCTION_FAILED;
goto error;
}
if (pthread_mutex_lock(&obj_list_mutex)) {
rc = CKR_FUNCTION_FAILED;
goto error;
}
rc = restore_private_token_object(hContext, buf, size, NULL);
(void) pthread_mutex_unlock(&obj_list_mutex);
if (rc != CKR_OK)
goto error;
free(buf);
(void) fclose(fp2);
}
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
return (CKR_OK);
error:
if (buf)
free(buf);
if (fp1) {
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
}
if (fp2)
(void) fclose(fp2);
return (rc);
}
static CK_RV
restore_private_token_object(
TSS_HCONTEXT hContext,
CK_BYTE *data,
CK_ULONG len,
OBJECT *pObj)
{
CK_BYTE * cleartxt = NULL;
CK_BYTE * obj_data = NULL;
CK_BYTE *ptr = NULL;
CK_BYTE hash_sha[SHA1_DIGEST_LENGTH];
UINT32 cleartxt_len;
UINT32 obj_data_len;
CK_RV rc;
/*
* format for the object data:
* (private flag has already been read at this point)
* ---- begin encrypted part
* length of object data (4 bytes)
* object data
* SHA of object data
* ---- end encrypted part
*/
cleartxt_len = len;
cleartxt = (CK_BYTE *)malloc(len);
if (!cleartxt) {
rc = CKR_HOST_MEMORY;
goto done;
}
rc = tpm_decrypt_data(hContext, hPrivateLeafKey, data, len,
cleartxt, &len);
if (rc != CKR_OK) {
goto done;
}
(void) strip_pkcs_padding(cleartxt, len, &cleartxt_len);
if (cleartxt_len > len) {
rc = CKR_FUNCTION_FAILED;
goto done;
}
ptr = cleartxt;
bcopy(ptr, &obj_data_len, sizeof (UINT32));
ptr += sizeof (UINT32);
obj_data = ptr;
if ((rc = compute_sha(ptr, obj_data_len, hash_sha)) != CKR_OK)
goto done;
ptr += obj_data_len;
if (memcmp((const void *)ptr, (const void *)hash_sha,
(size_t)SHA1_DIGEST_LENGTH) != 0) {
rc = CKR_FUNCTION_FAILED;
goto done;
}
(void) object_mgr_restore_obj(obj_data, pObj);
rc = CKR_OK;
done:
if (cleartxt)
free(cleartxt);
return (rc);
}
CK_RV
reload_token_object(TSS_HCONTEXT hContext, OBJECT *obj)
{
FILE *fp = NULL;
CK_BYTE *buf = NULL;
CK_BYTE fname[MAXPATHLEN];
CK_BBOOL priv;
UINT32 size;
CK_RV rc;
char *p = get_tpm_keystore_path();
if (p == NULL)
return (CKR_FUNCTION_FAILED);
(void) memset((char *)fname, 0x0, sizeof (fname));
(void) snprintf((char *)fname, sizeof (fname),
"%s/%s/", p, TOKEN_OBJ_DIR);
(void) strncat((char *)fname, (char *)obj->name, sizeof (fname));
fp = fopen((char *)fname, "r");
if (!fp) {
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (lockfile(fileno(fp), F_RDLCK)) {
rc = CKR_FUNCTION_FAILED;
goto done;
}
set_perm(fileno(fp));
(void) fread(&size, sizeof (UINT32), 1, fp);
(void) fread(&priv, sizeof (CK_BBOOL), 1, fp);
size = size - sizeof (UINT32) - sizeof (CK_BBOOL);
buf = (CK_BYTE *)malloc(size);
if (!buf) {
rc = CKR_HOST_MEMORY;
goto done;
}
(void) fread(buf, size, 1, fp);
if (priv) {
rc = restore_private_token_object(hContext, buf, size, obj);
} else {
rc = object_mgr_restore_obj(buf, obj);
}
done:
if (fp) {
(void) lockfile(fileno(fp), F_UNLCK);
(void) fclose(fp);
}
if (buf)
free(buf);
return (rc);
}
static int
islink(char *fname)
{
struct stat st;
if (stat((const char *)fname, &st))
return (-1);
else if (S_ISLNK(st.st_mode))
return (1);
return (0);
}
CK_RV
delete_token_object(OBJECT *obj)
{
FILE *fp1, *fp2;
CK_BYTE line[100];
char objidx[MAXPATHLEN], idxtmp[MAXPATHLEN], fname[MAXPATHLEN];
char *ksdir = get_tpm_keystore_path();
if (ksdir == NULL)
return (CKR_FUNCTION_FAILED);
(void) snprintf(objidx, sizeof (objidx),
"%s/%s/%s", ksdir, TOKEN_OBJ_DIR, TOKEN_OBJ_INDEX_FILE);
(void) snprintf(idxtmp, sizeof (idxtmp),
"%s/IDX.TMP", ksdir, TOKEN_OBJ_DIR);
/*
* If either file is a link, fail.
*/
if (islink(objidx) != 0)
return (CKR_FUNCTION_FAILED);
/*
* idxtmp is a temporary file (and should not exist yet), only fail
* if it is already an existing link.
*/
if (islink(idxtmp) == 1)
return (CKR_FUNCTION_FAILED);
fp1 = fopen(objidx, "r");
fp2 = fopen(idxtmp, "w");
if (!fp1 || !fp2) {
if (fp1)
(void) fclose(fp1);
if (fp2)
(void) fclose(fp2);
return (CKR_FUNCTION_FAILED);
}
if (lockfile(fileno(fp1), F_RDLCK)) {
(void) fclose(fp1);
(void) fclose(fp2);
return (CKR_FUNCTION_FAILED);
}
if (lockfile(fileno(fp2), F_WRLCK)) {
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
(void) fclose(fp2);
return (CKR_FUNCTION_FAILED);
}
set_perm(fileno(fp2));
while (!feof(fp1)) {
(void) fgets((char *)line, 50, fp1);
if (!feof(fp1)) {
line[ strlen((char *)line)-1 ] = 0;
if (strcmp((char *)line, (char *)obj->name))
(void) fprintf(fp2, "%s\n", line);
}
}
(void) lockfile(fileno(fp1), F_UNLCK);
(void) lockfile(fileno(fp2), F_UNLCK);
(void) fclose(fp1);
(void) fclose(fp2);
fp2 = fopen(objidx, "w");
fp1 = fopen(idxtmp, "r");
if (!fp1 || !fp2) {
if (fp1)
(void) fclose(fp1);
if (fp2)
(void) fclose(fp2);
return (CKR_FUNCTION_FAILED);
}
if (lockfile(fileno(fp1), F_RDLCK)) {
(void) fclose(fp1);
(void) fclose(fp2);
return (CKR_FUNCTION_FAILED);
}
if (lockfile(fileno(fp2), F_WRLCK)) {
(void) lockfile(fileno(fp1), F_UNLCK);
(void) fclose(fp1);
(void) fclose(fp2);
return (CKR_FUNCTION_FAILED);
}
set_perm(fileno(fp2));
while (!feof(fp1)) {
(void) fgets((char *)line, 50, fp1);
if (!feof(fp1))
(void) fprintf(fp2, "%s", (char *)line);
}
(void) lockfile(fileno(fp1), F_UNLCK);
(void) lockfile(fileno(fp2), F_UNLCK);
(void) fclose(fp1);
(void) fclose(fp2);
(void) snprintf(fname, sizeof (fname),
"%s/%s/%s", ksdir, TOKEN_OBJ_DIR, (char *)obj->name);
(void) unlink(fname);
return (CKR_OK);
}