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 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
1N/A */
1N/A
1N/A#include <pthread.h>
1N/A#include <string.h>
1N/A
1N/A#include <sys/types.h>
1N/A#include <sys/stat.h>
1N/A#include <uuid/uuid.h>
1N/A#include <fcntl.h>
1N/A#include <errno.h>
1N/A#include <pwd.h>
1N/A#include <syslog.h>
1N/A
1N/A#include <openssl/rsa.h>
1N/A
1N/A#include <tss/platform.h>
1N/A#include <tss/tss_defines.h>
1N/A#include <tss/tss_typedef.h>
1N/A#include <tss/tss_structs.h>
1N/A#include <tss/tss_error.h>
1N/A#include <tss/tcs_error.h>
1N/A#include <tss/tspi.h>
1N/A#include <trousers/trousers.h>
1N/A
1N/A#include "tpmtok_int.h"
1N/A#include "tpmtok_defs.h"
1N/A
1N/A#define MAX_RSA_KEYLENGTH 512
1N/A
1N/Aextern void stlogit(char *fmt, ...);
1N/A
1N/ACK_RV token_rng(TSS_HCONTEXT, CK_BYTE *, CK_ULONG);
1N/Aint tok_slot2local(CK_SLOT_ID);
1N/ACK_RV token_specific_session(CK_SLOT_ID);
1N/ACK_RV token_specific_final(TSS_HCONTEXT);
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_decrypt(
1N/A TSS_HCONTEXT,
1N/A CK_BYTE *,
1N/A CK_ULONG,
1N/A CK_BYTE *,
1N/A CK_ULONG *,
1N/A OBJECT *);
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_encrypt(
1N/A TSS_HCONTEXT,
1N/A CK_BYTE *,
1N/A CK_ULONG,
1N/A CK_BYTE *,
1N/A CK_ULONG *,
1N/A OBJECT *);
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_sign(
1N/A TSS_HCONTEXT,
1N/A CK_BYTE *,
1N/A CK_ULONG,
1N/A CK_BYTE *,
1N/A CK_ULONG *,
1N/A OBJECT *);
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_verify(TSS_HCONTEXT, CK_BYTE *,
1N/A CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *);
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_generate_keypair(TSS_HCONTEXT,
1N/A TEMPLATE *,
1N/A TEMPLATE *);
1N/A
1N/ACK_RV
1N/Atoken_specific_sha_init(DIGEST_CONTEXT *);
1N/A
1N/ACK_RV
1N/Atoken_specific_sha_update(DIGEST_CONTEXT *,
1N/A CK_BYTE *,
1N/A CK_ULONG);
1N/A
1N/ACK_RV
1N/Atoken_specific_sha_final(DIGEST_CONTEXT *,
1N/A CK_BYTE *,
1N/A CK_ULONG *);
1N/A
1N/ACK_RV token_specific_login(TSS_HCONTEXT, CK_USER_TYPE, CK_CHAR_PTR, CK_ULONG);
1N/ACK_RV token_specific_logout(TSS_HCONTEXT);
1N/ACK_RV token_specific_init_pin(TSS_HCONTEXT, CK_CHAR_PTR, CK_ULONG);
1N/ACK_RV token_specific_set_pin(ST_SESSION_HANDLE, CK_CHAR_PTR,
1N/A CK_ULONG, CK_CHAR_PTR, CK_ULONG);
1N/ACK_RV token_specific_verify_so_pin(TSS_HCONTEXT, CK_CHAR_PTR, CK_ULONG);
1N/A
1N/Astatic CK_RV
1N/Atoken_specific_init(char *, CK_SLOT_ID, TSS_HCONTEXT *);
1N/A
1N/Astruct token_specific_struct token_specific = {
1N/A "TPM_Debug",
1N/A &token_specific_init,
1N/A NULL,
1N/A &token_rng,
1N/A &token_specific_session,
1N/A &token_specific_final,
1N/A &token_specific_rsa_decrypt,
1N/A &token_specific_rsa_encrypt,
1N/A &token_specific_rsa_sign,
1N/A &token_specific_rsa_verify,
1N/A &token_specific_rsa_generate_keypair,
1N/A NULL,
1N/A NULL,
1N/A NULL,
1N/A &token_specific_login,
1N/A &token_specific_logout,
1N/A &token_specific_init_pin,
1N/A &token_specific_set_pin,
1N/A &token_specific_verify_so_pin
1N/A};
1N/A
1N/A/* The context we'll use globally to connect to the TSP */
1N/A
1N/A/* TSP key handles */
1N/ATSS_HKEY hPublicRootKey = NULL_HKEY;
1N/ATSS_HKEY hPublicLeafKey = NULL_HKEY;
1N/ATSS_HKEY hPrivateRootKey = NULL_HKEY;
1N/ATSS_HKEY hPrivateLeafKey = NULL_HKEY;
1N/A
1N/ATSS_UUID publicRootKeyUUID;
1N/ATSS_UUID publicLeafKeyUUID;
1N/ATSS_UUID privateRootKeyUUID;
1N/ATSS_UUID privateLeafKeyUUID;
1N/A
1N/A/* TSP policy handles */
1N/ATSS_HPOLICY hDefaultPolicy = NULL_HPOLICY;
1N/A
1N/A/* PKCS#11 key handles */
1N/Aint not_initialized = 0;
1N/A
1N/ACK_BYTE current_user_pin_sha[SHA1_DIGEST_LENGTH];
1N/ACK_BYTE current_so_pin_sha[SHA1_DIGEST_LENGTH];
1N/A
1N/Astatic TPM_CAP_VERSION_INFO tpmvinfo;
1N/A
1N/Astatic CK_RV
1N/Averify_user_pin(TSS_HCONTEXT, CK_BYTE *);
1N/A
1N/Astatic TSS_RESULT
1N/Atss_assign_secret_key_policy(TSS_HCONTEXT, TSS_FLAG, TSS_HKEY, CK_CHAR *);
1N/A
1N/Astatic TSS_RESULT
1N/Aset_legacy_key_params(TSS_HKEY);
1N/A
1N/Astatic void
1N/Alocal_uuid_clear(TSS_UUID *uuid)
1N/A{
1N/A if (uuid == NULL)
1N/A return;
1N/A (void) memset(uuid, 0, sizeof (TSS_UUID));
1N/A}
1N/A
1N/A
1N/A/* convert from TSS_UUID to uuid_t */
1N/Astatic void
1N/Atss_uuid_convert_from(TSS_UUID *uu, uuid_t ptr)
1N/A{
1N/A uint_t tmp;
1N/A uchar_t *out = ptr;
1N/A
1N/A tmp = ntohl(uu->ulTimeLow);
1N/A out[3] = (uchar_t)tmp;
1N/A tmp >>= 8;
1N/A out[2] = (uchar_t)tmp;
1N/A tmp >>= 8;
1N/A out[1] = (uchar_t)tmp;
1N/A tmp >>= 8;
1N/A out[0] = (uchar_t)tmp;
1N/A
1N/A tmp = ntohs(uu->usTimeMid);
1N/A out[5] = (uchar_t)tmp;
1N/A tmp >>= 8;
1N/A out[4] = (uchar_t)tmp;
1N/A
1N/A tmp = ntohs(uu->usTimeHigh);
1N/A out[7] = (uchar_t)tmp;
1N/A tmp >>= 8;
1N/A out[6] = (uchar_t)tmp;
1N/A
1N/A tmp = uu->bClockSeqHigh;
1N/A out[8] = (uchar_t)tmp;
1N/A tmp = uu->bClockSeqLow;
1N/A out[9] = (uchar_t)tmp;
1N/A
1N/A (void) memcpy(out+10, uu->rgbNode, 6);
1N/A}
1N/A
1N/A/* convert from uuid_t to TSS_UUID */
1N/Astatic void
1N/Atss_uuid_convert_to(TSS_UUID *uuid, uuid_t in)
1N/A{
1N/A uchar_t *ptr;
1N/A uint32_t ltmp;
1N/A uint16_t stmp;
1N/A
1N/A ptr = in;
1N/A
1N/A ltmp = *ptr++;
1N/A ltmp = (ltmp << 8) | *ptr++;
1N/A ltmp = (ltmp << 8) | *ptr++;
1N/A ltmp = (ltmp << 8) | *ptr++;
1N/A uuid->ulTimeLow = ntohl(ltmp);
1N/A
1N/A stmp = *ptr++;
1N/A stmp = (stmp << 8) | *ptr++;
1N/A uuid->usTimeMid = ntohs(stmp);
1N/A
1N/A stmp = *ptr++;
1N/A stmp = (stmp << 8) | *ptr++;
1N/A uuid->usTimeHigh = ntohs(stmp);
1N/A
1N/A uuid->bClockSeqHigh = *ptr++;
1N/A
1N/A uuid->bClockSeqLow = *ptr++;
1N/A
1N/A (void) memcpy(uuid->rgbNode, ptr, 6);
1N/A}
1N/A
1N/Astatic void
1N/Alocal_uuid_copy(TSS_UUID *dst, TSS_UUID *src)
1N/A{
1N/A uuid_t udst, usrc;
1N/A
1N/A tss_uuid_convert_from(dst, udst);
1N/A tss_uuid_convert_from(src, usrc);
1N/A
1N/A uuid_copy(udst, usrc);
1N/A
1N/A tss_uuid_convert_to(dst, udst);
1N/A}
1N/A
1N/Astatic void
1N/Alocal_uuid_generate(TSS_UUID *uu)
1N/A{
1N/A uuid_t newuuid;
1N/A
1N/A uuid_generate(newuuid);
1N/A
1N/A tss_uuid_convert_to(uu, newuuid);
1N/A}
1N/A
1N/Astatic int
1N/Alocal_copy_file(char *dst, char *src)
1N/A{
1N/A FILE *fdest, *fsrc;
1N/A char line[BUFSIZ];
1N/A
1N/A fdest = fopen(dst, "w");
1N/A if (fdest == NULL)
1N/A return (-1);
1N/A
1N/A fsrc = fopen(src, "r");
1N/A if (fsrc == NULL) {
1N/A (void) fclose(fdest);
1N/A return (-1);
1N/A }
1N/A
1N/A while (fread(line, sizeof (line), 1, fsrc))
1N/A (void) fprintf(fdest, "%s\n", line);
1N/A (void) fclose(fsrc);
1N/A (void) fclose(fdest);
1N/A return (0);
1N/A}
1N/A
1N/Astatic int
1N/Aremove_uuid(char *keyname)
1N/A{
1N/A int ret = 0;
1N/A FILE *fp, *newfp;
1N/A char fname[MAXPATHLEN];
1N/A char line[BUFSIZ], key[BUFSIZ], idstr[BUFSIZ];
1N/A char *tmpfname;
1N/A char *p = get_tpm_keystore_path();
1N/A
1N/A if (p == NULL)
1N/A return (-1);
1N/A
1N/A (void) snprintf(fname, sizeof (fname),
1N/A "%s/%s", p, TPMTOK_UUID_INDEX_FILENAME);
1N/A
1N/A fp = fopen(fname, "r");
1N/A if (fp == NULL) {
1N/A return (-1);
1N/A }
1N/A
1N/A tmpfname = tempnam("/tmp", "tpmtok");
1N/A newfp = fopen(tmpfname, "w+");
1N/A if (newfp == NULL) {
1N/A free(tmpfname);
1N/A (void) fclose(fp);
1N/A return (-1);
1N/A }
1N/A
1N/A while (!feof(fp)) {
1N/A (void) fgets(line, sizeof (line), fp);
1N/A if (sscanf(line, "%1024s %1024s", key, idstr) == 2) {
1N/A if (strcmp(key, keyname))
1N/A (void) fprintf(newfp, "%s\n", line);
1N/A }
1N/A }
1N/A
1N/A (void) fclose(fp);
1N/A (void) fclose(newfp);
1N/A if (local_copy_file(fname, tmpfname) == 0)
1N/A (void) unlink(tmpfname);
1N/A
1N/A free(tmpfname);
1N/A
1N/A return (ret);
1N/A}
1N/A
1N/Astatic int
1N/Afind_uuid(char *keyname, TSS_UUID *uu)
1N/A{
1N/A int ret = 0, found = 0;
1N/A FILE *fp = NULL;
1N/A char fname[MAXPATHLEN];
1N/A char line[BUFSIZ], key[BUFSIZ], idstr[BUFSIZ];
1N/A uuid_t uuid;
1N/A char *p = get_tpm_keystore_path();
1N/A
1N/A if (p == NULL)
1N/A return (-1);
1N/A
1N/A tss_uuid_convert_from(uu, uuid);
1N/A
1N/A (void) snprintf(fname, sizeof (fname),
1N/A "%s/%s", p, TPMTOK_UUID_INDEX_FILENAME);
1N/A
1N/A /* Open UUID Index file */
1N/A fp = fopen(fname, "r");
1N/A if (fp == NULL) {
1N/A if (errno == ENOENT) {
1N/A /* initialize the file */
1N/A fp = fopen(fname, "w");
1N/A if (fp != NULL)
1N/A (void) fclose(fp);
1N/A }
1N/A return (-1);
1N/A }
1N/A
1N/A while (!feof(fp)) {
1N/A (void) fgets(line, sizeof (line), fp);
1N/A if (sscanf(line, "%1024s %1024s", key, idstr) == 2) {
1N/A if (strcmp(key, keyname) == 0) {
1N/A ret = uuid_parse(idstr, uuid);
1N/A if (ret == 0) {
1N/A found = 1;
1N/A tss_uuid_convert_to(uu,
1N/A uuid);
1N/A }
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A (void) fclose(fp);
1N/A
1N/A if (!found)
1N/A ret = -1;
1N/A return (ret);
1N/A}
1N/A
1N/Astatic int
1N/Alocal_uuid_is_null(TSS_UUID *uu)
1N/A{
1N/A uuid_t uuid;
1N/A int nulluuid;
1N/A
1N/A tss_uuid_convert_from(uu, uuid);
1N/A
1N/A nulluuid = uuid_is_null(uuid);
1N/A return (nulluuid);
1N/A}
1N/A
1N/Astatic int
1N/Aadd_uuid(char *keyname, TSS_UUID *uu)
1N/A{
1N/A FILE *fp = NULL;
1N/A char fname[MAXPATHLEN];
1N/A char idstr[BUFSIZ];
1N/A uuid_t uuid;
1N/A char *p = get_tpm_keystore_path();
1N/A
1N/A if (p == NULL)
1N/A return (-1);
1N/A
1N/A tss_uuid_convert_from(uu, uuid);
1N/A
1N/A if (uuid_is_null(uuid))
1N/A return (-1);
1N/A
1N/A uuid_unparse(uuid, idstr);
1N/A
1N/A (void) snprintf(fname, sizeof (fname),
1N/A "%s/%s", p, TPMTOK_UUID_INDEX_FILENAME);
1N/A
1N/A fp = fopen(fname, "a");
1N/A if (fp == NULL)
1N/A return (-1);
1N/A
1N/A (void) fprintf(fp, "%s %s\n", keyname, idstr);
1N/A (void) fclose(fp);
1N/A
1N/A return (0);
1N/A}
1N/A
1N/A
1N/Astatic UINT32
1N/Autil_get_keysize_flag(CK_ULONG size)
1N/A{
1N/A switch (size) {
1N/A case 512:
1N/A return (TSS_KEY_SIZE_512);
1N/A /* NOTREACHED */
1N/A break;
1N/A case 1024:
1N/A return (TSS_KEY_SIZE_1024);
1N/A /* NOTREACHED */
1N/A break;
1N/A case 2048:
1N/A return (TSS_KEY_SIZE_2048);
1N/A /* NOTREACHED */
1N/A break;
1N/A default:
1N/A break;
1N/A }
1N/A
1N/A return (0);
1N/A}
1N/A
1N/A/* make sure the public exponent attribute is 65537 */
1N/Astatic CK_ULONG
1N/Autil_check_public_exponent(TEMPLATE *tmpl)
1N/A{
1N/A CK_BBOOL flag;
1N/A CK_ATTRIBUTE *publ_exp_attr;
1N/A CK_BYTE pubexp_bytes[] = { 1, 0, 1 };
1N/A CK_ULONG publ_exp, rc = 1;
1N/A
1N/A flag = template_attribute_find(tmpl, CKA_PUBLIC_EXPONENT,
1N/A &publ_exp_attr);
1N/A if (!flag) {
1N/A LogError1("Couldn't find public exponent attribute");
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A
1N/A switch (publ_exp_attr->ulValueLen) {
1N/A case 3:
1N/A rc = memcmp(pubexp_bytes, publ_exp_attr->pValue, 3);
1N/A break;
1N/A case sizeof (CK_ULONG):
1N/A publ_exp = *((CK_ULONG *)publ_exp_attr->pValue);
1N/A if (publ_exp == 65537)
1N/A rc = 0;
1N/A break;
1N/A default:
1N/A break;
1N/A }
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/ATSS_RESULT
1N/Aset_public_modulus(TSS_HCONTEXT hContext, TSS_HKEY hKey,
1N/A unsigned long size_n, unsigned char *n)
1N/A{
1N/A UINT64 offset;
1N/A UINT32 blob_size;
1N/A BYTE *blob, pub_blob[1024];
1N/A TCPA_PUBKEY pub_key;
1N/A TSS_RESULT result;
1N/A
1N/A /* Get the TCPA_PUBKEY blob from the key object. */
1N/A result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
1N/A TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blob_size, &blob);
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_GetAttribData failed: rc=0x%0x - %s\n",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A offset = 0;
1N/A result = Trspi_UnloadBlob_PUBKEY(&offset, blob, &pub_key);
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Trspi_UnloadBlob_PUBKEY failed: rc=0x%0x - %s\n",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A Tspi_Context_FreeMemory(hContext, blob);
1N/A /* Free the first dangling reference, putting 'n' in its place */
1N/A free(pub_key.pubKey.key);
1N/A pub_key.pubKey.keyLength = size_n;
1N/A pub_key.pubKey.key = n;
1N/A
1N/A offset = 0;
1N/A Trspi_LoadBlob_PUBKEY(&offset, pub_blob, &pub_key);
1N/A
1N/A /* Free the second dangling reference */
1N/A free(pub_key.algorithmParms.parms);
1N/A
1N/A /* set the public key data in the TSS object */
1N/A result = Tspi_SetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
1N/A TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, (UINT32)offset, pub_blob);
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_SetAttribData failed: rc=0x%0x - %s\n",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A return (result);
1N/A}
1N/A
1N/A/*
1N/A * Get details about the TPM to put into the token_info structure.
1N/A */
1N/ACK_RV
1N/Atoken_get_tpm_info(TSS_HCONTEXT hContext, TOKEN_DATA *td)
1N/A{
1N/A TSS_RESULT result;
1N/A TPM_CAPABILITY_AREA capArea = TSS_TPMCAP_VERSION_VAL;
1N/A UINT32 datalen;
1N/A BYTE *data;
1N/A TSS_HTPM hTPM;
1N/A
1N/A if ((result = Tspi_Context_GetTpmObject(hContext, &hTPM))) {
1N/A stlogit("Tspi_Context_GetTpmObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A if ((result = Tspi_TPM_GetCapability(hTPM,
1N/A capArea, 0, NULL, &datalen, &data)) != 0 || datalen == 0 ||
1N/A data == NULL) {
1N/A stlogit("Tspi_Context_GetCapability: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A if (datalen > sizeof (tpmvinfo)) {
1N/A Tspi_Context_FreeMemory(hContext, data);
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A (void) memcpy(&tpmvinfo, (void *)data, datalen);
1N/A
1N/A bzero(td->token_info.manufacturerID,
1N/A sizeof (td->token_info.manufacturerID));
1N/A
1N/A (void) memset(td->token_info.manufacturerID, ' ',
1N/A sizeof (td->token_info.manufacturerID) - 1);
1N/A
1N/A (void) memcpy(td->token_info.manufacturerID,
1N/A tpmvinfo.tpmVendorID, sizeof (tpmvinfo.tpmVendorID));
1N/A
1N/A (void) memset(td->token_info.label, ' ',
1N/A sizeof (td->token_info.label) - 1);
1N/A
1N/A (void) memcpy(td->token_info.label, "TPM", 3);
1N/A
1N/A td->token_info.hardwareVersion.major = tpmvinfo.version.major;
1N/A td->token_info.hardwareVersion.minor = tpmvinfo.version.minor;
1N/A td->token_info.firmwareVersion.major = tpmvinfo.version.revMajor;
1N/A td->token_info.firmwareVersion.minor = tpmvinfo.version.revMinor;
1N/A
1N/A Tspi_Context_FreeMemory(hContext, data);
1N/A return (CKR_OK);
1N/A}
1N/A
1N/A/*ARGSUSED*/
1N/ACK_RV
1N/Atoken_specific_session(CK_SLOT_ID slotid)
1N/A{
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_rng(TSS_HCONTEXT hContext, CK_BYTE *output, CK_ULONG bytes)
1N/A{
1N/A TSS_RESULT rc;
1N/A TSS_HTPM hTPM;
1N/A BYTE *random_bytes = NULL;
1N/A
1N/A if ((rc = Tspi_Context_GetTpmObject(hContext, &hTPM))) {
1N/A stlogit("Tspi_Context_GetTpmObject: 0x%0x - %s",
1N/A rc, Trspi_Error_String(rc));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((rc = Tspi_TPM_GetRandom(hTPM, bytes, &random_bytes))) {
1N/A stlogit("Tspi_TPM_GetRandom: 0x%0x - %s",
1N/A rc, Trspi_Error_String(rc));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A (void) memcpy(output, random_bytes, bytes);
1N/A Tspi_Context_FreeMemory(hContext, random_bytes);
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ATSS_RESULT
1N/Aopen_tss_context(TSS_HCONTEXT *pContext)
1N/A{
1N/A TSS_RESULT result;
1N/A
1N/A if ((result = Tspi_Context_Create(pContext))) {
1N/A stlogit("Tspi_Context_Create: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_Context_Connect(*pContext, NULL))) {
1N/A stlogit("Tspi_Context_Connect: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_Close(*pContext);
1N/A *pContext = 0;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A return (result);
1N/A}
1N/A
1N/A/*ARGSUSED*/
1N/Astatic CK_RV
1N/Atoken_specific_init(char *Correlator, CK_SLOT_ID SlotNumber,
1N/A TSS_HCONTEXT *hContext)
1N/A{
1N/A TSS_RESULT result;
1N/A
1N/A result = open_tss_context(hContext);
1N/A if (result)
1N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A if ((result = Tspi_Context_GetDefaultPolicy(*hContext,
1N/A &hDefaultPolicy))) {
1N/A stlogit("Tspi_Context_GetDefaultPolicy: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A local_uuid_clear(&publicRootKeyUUID);
1N/A local_uuid_clear(&privateRootKeyUUID);
1N/A local_uuid_clear(&publicLeafKeyUUID);
1N/A local_uuid_clear(&privateLeafKeyUUID);
1N/A
1N/A result = token_get_tpm_info(*hContext, nv_token_data);
1N/A return (result);
1N/A}
1N/A
1N/A/*
1N/A * Given a modulus and prime from an RSA key, create a TSS_HKEY object by
1N/A * wrapping the RSA key with a key from the TPM (SRK or other previously stored
1N/A * key).
1N/A */
1N/Astatic CK_RV
1N/Atoken_wrap_sw_key(
1N/A TSS_HCONTEXT hContext,
1N/A int size_n,
1N/A unsigned char *n,
1N/A int size_p,
1N/A unsigned char *p,
1N/A TSS_HKEY hParentKey,
1N/A TSS_FLAG initFlags,
1N/A TSS_HKEY *phKey)
1N/A{
1N/A TSS_RESULT result;
1N/A UINT32 key_size;
1N/A
1N/A key_size = util_get_keysize_flag(size_n * 8);
1N/A if (initFlags == 0) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* create the TSS key object */
1N/A result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
1N/A TSS_KEY_MIGRATABLE | initFlags | key_size, phKey);
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A result = set_public_modulus(hContext, *phKey, size_n, n);
1N/A if (result != TSS_SUCCESS) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A *phKey = NULL_HKEY;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* set the private key data in the TSS object */
1N/A result = Tspi_SetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB,
1N/A TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, size_p, p);
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_SetAttribData: 0x%x - %s",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A *phKey = NULL_HKEY;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A result = tss_assign_secret_key_policy(hContext, TSS_POLICY_MIGRATION,
1N/A *phKey, NULL);
1N/A
1N/A if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) {
1N/A if ((result = Tspi_SetAttribUint32(*phKey,
1N/A TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
1N/A TSS_ES_RSAESPKCSV15))) {
1N/A stlogit("Tspi_SetAttribUint32: 0x%0x - %s\n",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_SetAttribUint32(*phKey,
1N/A TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
1N/A TSS_SS_RSASSAPKCS1V15_DER))) {
1N/A stlogit("Tspi_SetAttribUint32: 0x%0x - %s\n",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A }
1N/A
1N/A result = Tspi_Key_WrapKey(*phKey, hParentKey, NULL_HPCRS);
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_Key_WrapKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A *phKey = NULL_HKEY;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/A/*
1N/A * Create a TPM key blob for an imported key. This function is only called when
1N/A * a key is in active use, so any failure should trickle through.
1N/A */
1N/Astatic CK_RV
1N/Atoken_wrap_key_object(TSS_HCONTEXT hContext,
1N/A CK_OBJECT_HANDLE ckObject,
1N/A TSS_HKEY hParentKey, TSS_HKEY *phKey)
1N/A{
1N/A CK_RV rc = CKR_OK;
1N/A CK_ATTRIBUTE *attr = NULL, *new_attr, *prime_attr;
1N/A CK_ULONG class, key_type;
1N/A OBJECT *obj;
1N/A
1N/A TSS_RESULT result;
1N/A TSS_FLAG initFlags = 0;
1N/A BYTE *rgbBlob;
1N/A UINT32 ulBlobLen;
1N/A
1N/A if ((rc = object_mgr_find_in_map1(hContext, ckObject, &obj))) {
1N/A return (rc);
1N/A }
1N/A
1N/A /* if the object isn't a key, fail */
1N/A if (template_attribute_find(obj->template, CKA_KEY_TYPE,
1N/A &attr) == FALSE) {
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A
1N/A key_type = *((CK_ULONG *)attr->pValue);
1N/A
1N/A if (key_type != CKK_RSA) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A if (template_attribute_find(obj->template, CKA_CLASS,
1N/A &attr) == FALSE) {
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A
1N/A class = *((CK_ULONG *)attr->pValue);
1N/A
1N/A if (class == CKO_PRIVATE_KEY) {
1N/A /*
1N/A * In order to create a full TSS key blob using a PKCS#11
1N/A * private key object, we need one of the two primes, the
1N/A * modulus and the private exponent and we need the public
1N/A * exponent to be correct.
1N/A */
1N/A
1N/A /*
1N/A * Check the least likely attribute to exist first, the
1N/A * primes.
1N/A */
1N/A if (template_attribute_find(obj->template, CKA_PRIME_1,
1N/A &prime_attr) == FALSE) {
1N/A if (template_attribute_find(obj->template,
1N/A CKA_PRIME_2, &prime_attr) == FALSE) {
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A }
1N/A
1N/A /* Make sure the public exponent is usable */
1N/A if ((rc = util_check_public_exponent(obj->template))) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A /* get the modulus */
1N/A if (template_attribute_find(obj->template, CKA_MODULUS,
1N/A &attr) == FALSE) {
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A
1N/A /* make sure the key size is usable */
1N/A initFlags = util_get_keysize_flag(attr->ulValueLen * 8);
1N/A if (initFlags == 0) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A /* generate the software based key */
1N/A if ((rc = token_wrap_sw_key(hContext,
1N/A (int)attr->ulValueLen, attr->pValue,
1N/A (int)prime_attr->ulValueLen, prime_attr->pValue,
1N/A hParentKey, TSS_KEY_TYPE_LEGACY | TSS_KEY_NO_AUTHORIZATION,
1N/A phKey))) {
1N/A return (rc);
1N/A }
1N/A } else if (class == CKO_PUBLIC_KEY) {
1N/A /* Make sure the public exponent is usable */
1N/A if ((util_check_public_exponent(obj->template))) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A /* grab the modulus to put into the TSS key object */
1N/A if (template_attribute_find(obj->template,
1N/A CKA_MODULUS, &attr) == FALSE) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A /* make sure the key size is usable */
1N/A initFlags = util_get_keysize_flag(attr->ulValueLen * 8);
1N/A if (initFlags == 0) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A initFlags |= TSS_KEY_MIGRATABLE | TSS_KEY_NO_AUTHORIZATION |
1N/A TSS_KEY_TYPE_LEGACY;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_RSAKEY, initFlags, phKey))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A if ((result = set_public_modulus(hContext, *phKey,
1N/A attr->ulValueLen, attr->pValue))) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A *phKey = NULL_HKEY;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A result = tss_assign_secret_key_policy(hContext,
1N/A TSS_POLICY_MIGRATION, *phKey, NULL);
1N/A if (result) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A *phKey = NULL_HKEY;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A result = set_legacy_key_params(*phKey);
1N/A if (result) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A *phKey = NULL_HKEY;
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A } else {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* grab the entire key blob to put into the PKCS#11 object */
1N/A if ((result = Tspi_GetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB,
1N/A TSS_TSPATTRIB_KEYBLOB_BLOB, &ulBlobLen, &rgbBlob))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* insert the key blob into the object */
1N/A if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen,
1N/A &new_attr))) {
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(obj->template, new_attr);
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A
1N/A /*
1N/A * If this is a token object, save it with the new attribute
1N/A * so that we don't have to go down this path again.
1N/A */
1N/A if (!object_is_session_object(obj)) {
1N/A rc = save_token_object(hContext, obj);
1N/A }
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/Astatic TSS_RESULT
1N/Atss_assign_secret_key_policy(TSS_HCONTEXT hContext, TSS_FLAG policyType,
1N/A TSS_HKEY hKey, CK_CHAR *passHash)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HPOLICY hPolicy;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_POLICY, policyType, &hPolicy))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A if ((result = Tspi_Policy_AssignToObject(hPolicy, hKey))) {
1N/A stlogit("Tspi_Policy_AssignToObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/A if (passHash == NULL) {
1N/A result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE,
1N/A 0, NULL);
1N/A } else {
1N/A result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
1N/A SHA1_DIGEST_LENGTH, passHash);
1N/A }
1N/A if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/Adone:
1N/A if (result != TSS_SUCCESS)
1N/A Tspi_Context_CloseObject(hContext, hPolicy);
1N/A return (result);
1N/A}
1N/A
1N/A/*
1N/A * Take a key from the TSS store (on-disk) and load it into the TPM, wrapped
1N/A * by an already TPM-resident key and protected with a PIN (optional).
1N/A */
1N/Astatic CK_RV
1N/Atoken_load_key(
1N/A TSS_HCONTEXT hContext,
1N/A CK_OBJECT_HANDLE ckKey,
1N/A TSS_HKEY hParentKey,
1N/A CK_CHAR_PTR passHash,
1N/A TSS_HKEY *phKey)
1N/A{
1N/A TSS_RESULT result;
1N/A CK_RV rc;
1N/A
1N/A /*
1N/A * The key blob wasn't found, load the parts of the key
1N/A * from the object DB and create a new key object that
1N/A * gets loaded into the TPM, wrapped with the parent key.
1N/A */
1N/A if ((rc = token_wrap_key_object(hContext, ckKey,
1N/A hParentKey, phKey))) {
1N/A return (rc);
1N/A }
1N/A
1N/A /*
1N/A * Assign the PIN hash (optional) to the newly loaded key object,
1N/A * if this PIN is incorrect, the TPM will not be able to decrypt
1N/A * the private key and use it.
1N/A */
1N/A result = tss_assign_secret_key_policy(hContext, TSS_POLICY_USAGE,
1N/A *phKey, passHash);
1N/A
1N/A return (result);
1N/A}
1N/A
1N/A/*
1N/A * Load the SRK into the TPM by referencing its well-known UUID and using the
1N/A * default SRK PIN (20 bytes of 0x00).
1N/A *
1N/A * NOTE - if the SRK PIN is changed by an administrative tool, this code will
1N/A * fail because it assumes that the well-known PIN is still being used.
1N/A */
1N/Astatic TSS_RESULT
1N/Atoken_load_srk(TSS_HCONTEXT hContext, TSS_HKEY *hSRK)
1N/A{
1N/A TSS_HPOLICY hPolicy;
1N/A TSS_RESULT result;
1N/A TSS_UUID SRK_UUID = TSS_UUID_SRK;
1N/A BYTE wellKnown[] = TSS_WELL_KNOWN_SECRET;
1N/A TSS_HTPM hTPM;
1N/A
1N/A if ((result = Tspi_Context_GetTpmObject(hContext, &hTPM))) {
1N/A stlogit("Tspi_Context_GetTpmObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* load the SRK */
1N/A if ((result = Tspi_Context_LoadKeyByUUID(hContext,
1N/A TSS_PS_TYPE_SYSTEM, SRK_UUID, hSRK))) {
1N/A stlogit("Tspi_Context_LoadKeyByUUID: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/A if ((result = Tspi_GetPolicyObject(*hSRK, TSS_POLICY_USAGE,
1N/A &hPolicy))) {
1N/A stlogit("Tspi_GetPolicyObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/A if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
1N/A sizeof (wellKnown), wellKnown))) {
1N/A stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/A
1N/Adone:
1N/A return (result);
1N/A}
1N/A
1N/Astatic TSS_RESULT
2N/Aload_mrk(TSS_HCONTEXT hContext, TSS_HKEY hParent, TSS_HKEY *hKey)
2N/A{
2N/A TSS_RESULT ret;
2N/A TSS_UUID mrk_uuid = TSS_UUID_MRK;
2N/A
2N/A ret = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM,
2N/A mrk_uuid, hKey);
2N/A
2N/A if (ret != TSS_SUCCESS) {
2N/A /*
2N/A * The MRK doesn't exist yet, so use the parent key,
2N/A * which is the SRK. This is to preserve compatibility
2N/A * for systems that already had an established TPM
2N/A * prior to the introduction of the MRK.
2N/A */
2N/A *hKey = hParent;
2N/A return (TSS_SUCCESS);
2N/A }
2N/A
2N/A ret = Tspi_Key_LoadKey(*hKey, hParent);
2N/A if (ret) {
2N/A stlogit("Unable to load key: %s\n",
2N/A Trspi_Error_String(ret));
2N/A Tspi_Context_CloseObject(hContext, *hKey);
2N/A return (ret);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/Astatic TSS_RESULT
1N/Atss_find_and_load_key(TSS_HCONTEXT hContext,
1N/A char *keyid, TSS_UUID *uuid, TSS_HKEY hParent,
1N/A BYTE *hash, TSS_HKEY *hKey)
1N/A{
1N/A TSS_RESULT result;
1N/A
1N/A if (local_uuid_is_null(uuid) &&
1N/A find_uuid(keyid, uuid)) {
1N/A /* The UUID was not created or saved yet */
1N/A return (1);
1N/A }
1N/A result = Tspi_Context_GetKeyByUUID(hContext,
1N/A TSS_PS_TYPE_USER, *uuid, hKey);
1N/A if (result) {
1N/A stlogit("Tspi_Context_GetKeyByUUID: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A if (hash != NULL) {
1N/A result = tss_assign_secret_key_policy(hContext,
1N/A TSS_POLICY_USAGE, *hKey, (CK_BYTE *)hash);
1N/A if (result)
1N/A return (result);
1N/A }
1N/A
1N/A result = Tspi_Key_LoadKey(*hKey, hParent);
1N/A if (result)
1N/A stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A
1N/A return (result);
1N/A}
1N/A
1N/Astatic TSS_RESULT
1N/Atoken_load_public_root_key(TSS_HCONTEXT hContext)
1N/A{
1N/A TSS_RESULT result;
2N/A TSS_HKEY hSRK, hMRK;
1N/A
1N/A if (hPublicRootKey != NULL_HKEY)
1N/A return (TSS_SUCCESS);
1N/A
1N/A if ((result = token_load_srk(hContext, &hSRK))) {
1N/A return (result);
1N/A }
2N/A if ((result = load_mrk(hContext, hSRK, &hMRK)))
2N/A return (result);
1N/A
1N/A result = tss_find_and_load_key(hContext,
1N/A TPMTOK_PUBLIC_ROOT_KEY_ID,
2N/A &publicRootKeyUUID, hMRK, NULL, &hPublicRootKey);
1N/A if (result)
1N/A return (result);
1N/A
1N/A return (result);
1N/A}
1N/A
1N/Astatic TSS_RESULT
1N/Aset_legacy_key_params(TSS_HKEY hKey)
1N/A{
1N/A TSS_RESULT result;
1N/A
1N/A if ((result = Tspi_SetAttribUint32(hKey,
1N/A TSS_TSPATTRIB_KEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
1N/A TSS_ES_RSAESPKCSV15))) {
1N/A stlogit("Tspi_SetAttribUint32: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A if ((result = Tspi_SetAttribUint32(hKey,
1N/A TSS_TSPATTRIB_KEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
1N/A TSS_SS_RSASSAPKCS1V15_DER))) {
1N/A stlogit("Tspi_SetAttribUint32: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A return (result);
1N/A}
1N/A
1N/Astatic TSS_RESULT
1N/Atss_generate_key(TSS_HCONTEXT hContext, TSS_FLAG initFlags, BYTE *passHash,
1N/A TSS_HKEY hParentKey, TSS_HKEY *phKey)
1N/A{
1N/A TSS_RESULT result;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_RSAKEY, initFlags, phKey))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
2N/A if (initFlags & TSS_KEY_AUTHORIZATION) {
2N/A result = tss_assign_secret_key_policy(hContext,
2N/A TSS_POLICY_USAGE, *phKey, passHash);
2N/A if (result) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A return (result);
1N/A }
2N/A }
2N/A
2N/A if (initFlags & TSS_KEY_MIGRATABLE) {
2N/A result = tss_assign_secret_key_policy(hContext,
2N/A TSS_POLICY_MIGRATION, *phKey, passHash);
2N/A if (result) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A return (result);
1N/A }
1N/A }
1N/A
1N/A if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) {
1N/A result = set_legacy_key_params(*phKey);
1N/A if (result) {
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A return (result);
1N/A }
1N/A }
1N/A
1N/A if ((result = Tspi_Key_CreateKey(*phKey, hParentKey, 0))) {
1N/A stlogit("Tspi_Key_CreateKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, *phKey);
1N/A }
1N/A
1N/A return (result);
1N/A}
1N/A
1N/Astatic TSS_RESULT
1N/Atss_change_auth(
1N/A TSS_HCONTEXT hContext,
1N/A TSS_HKEY hObjectToChange, TSS_HKEY hParentObject,
1N/A TSS_UUID objUUID, TSS_UUID parentUUID,
1N/A CK_CHAR *passHash)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HPOLICY hPolicy;
1N/A TSS_HKEY oldkey;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hPolicy))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
1N/A SHA1_DIGEST_LENGTH, passHash))) {
1N/A stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A if ((result = Tspi_ChangeAuth(hObjectToChange, hParentObject,
1N/A hPolicy))) {
1N/A stlogit("Tspi_ChangeAuth: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A }
1N/A /*
1N/A * Update the PS key by unregistering the key UUID and then
1N/A * re-registering with the same UUID. This forces the updated
1N/A * auth data associated with the key to be stored in PS so
1N/A * the new PIN can be used next time.
1N/A */
1N/A if ((result = Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, objUUID, &oldkey)))
1N/A stlogit("Tspi_Context_UnregisterKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A
1N/A if ((result = Tspi_Context_RegisterKey(hContext, hObjectToChange,
1N/A TSS_PS_TYPE_USER, objUUID, TSS_PS_TYPE_USER, parentUUID)))
1N/A stlogit("Tspi_Context_RegisterKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A
1N/A return (result);
1N/A}
1N/A
1N/Astatic CK_RV
1N/Atoken_generate_leaf_key(TSS_HCONTEXT hContext,
1N/A int key_type, CK_CHAR_PTR passHash, TSS_HKEY *phKey)
1N/A{
1N/A CK_RV rc = CKR_FUNCTION_FAILED;
1N/A TSS_RESULT result;
1N/A TSS_HKEY hParentKey;
1N/A TSS_UUID newuuid, parentUUID;
1N/A char *keyid;
1N/A TSS_FLAG initFlags = TSS_KEY_MIGRATABLE |
1N/A TSS_KEY_TYPE_BIND | TSS_KEY_SIZE_2048 | TSS_KEY_AUTHORIZATION;
1N/A
1N/A switch (key_type) {
1N/A case TPMTOK_PUBLIC_LEAF_KEY:
1N/A hParentKey = hPublicRootKey;
1N/A keyid = TPMTOK_PUBLIC_LEAF_KEY_ID;
1N/A local_uuid_copy(&parentUUID, &publicRootKeyUUID);
1N/A break;
1N/A case TPMTOK_PRIVATE_LEAF_KEY:
1N/A hParentKey = hPrivateRootKey;
1N/A keyid = TPMTOK_PRIVATE_LEAF_KEY_ID;
1N/A local_uuid_copy(&parentUUID, &privateRootKeyUUID);
1N/A break;
1N/A default:
1N/A stlogit("Unknown key type 0x%0x", key_type);
1N/A goto done;
1N/A /* NOTREACHED */
1N/A break;
1N/A }
1N/A
1N/A if (result = tss_generate_key(hContext, initFlags, passHash,
1N/A hParentKey, phKey)) {
1N/A return (rc);
1N/A }
1N/A
1N/A /*
1N/A * - generate newUUID
1N/A * - Tspi_Context_RegisterKey(hContext, hPrivateRootKey,
1N/A * USER, newUUID, USER, parentUUID);
1N/A * - store newUUID
1N/A */
1N/A (void) local_uuid_generate(&newuuid);
1N/A
1N/A result = Tspi_Context_RegisterKey(hContext, *phKey,
1N/A TSS_PS_TYPE_USER, newuuid,
1N/A TSS_PS_TYPE_USER, parentUUID);
1N/A if (result == TSS_SUCCESS) {
1N/A int ret;
1N/A /*
1N/A * Add the UUID to the token UUID index.
1N/A */
1N/A ret = add_uuid(keyid, &newuuid);
1N/A
1N/A if (ret)
1N/A result = Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, newuuid, phKey);
1N/A else
1N/A rc = CKR_OK;
1N/A }
1N/A
1N/Adone:
1N/A return (rc);
1N/A}
1N/A
1N/A/*
1N/A * PINs are verified by attempting to bind/unbind random data using a
1N/A * TPM resident key that has the PIN being tested assigned as its "secret".
1N/A * If the PIN is incorrect, the unbind operation will fail.
1N/A */
1N/Astatic CK_RV
1N/Atoken_verify_pin(TSS_HCONTEXT hContext, TSS_HKEY hKey)
1N/A{
1N/A TSS_HENCDATA hEncData;
1N/A UINT32 ulUnboundDataLen;
1N/A BYTE *rgbUnboundData = NULL;
1N/A BYTE rgbData[16];
1N/A TSS_RESULT result;
1N/A CK_RV rc = CKR_FUNCTION_FAILED;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/A
1N/A /* Use some random data */
1N/A rc = token_rng(hContext, rgbData, sizeof (rgbData));
1N/A if (rc)
1N/A goto done;
1N/A
1N/A if ((result = Tspi_Data_Bind(hEncData, hKey,
1N/A sizeof (rgbData), rgbData))) {
1N/A stlogit("Tspi_Data_Bind: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A }
1N/A
1N/A /* unbind the junk data to test the key's auth data */
1N/A result = Tspi_Data_Unbind(hEncData, hKey, &ulUnboundDataLen,
1N/A &rgbUnboundData);
1N/A if (result == TPM_E_AUTHFAIL) {
1N/A rc = CKR_PIN_INCORRECT;
1N/A stlogit("Tspi_Data_Unbind: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A goto done;
1N/A } else if (result != TSS_SUCCESS) {
1N/A stlogit("Tspi_Data_Unbind: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A rc = CKR_FUNCTION_FAILED;
1N/A goto done;
1N/A }
1N/A
1N/A if (memcmp(rgbUnboundData, rgbData, ulUnboundDataLen))
1N/A rc = CKR_PIN_INCORRECT;
1N/A else
1N/A rc = CKR_OK;
1N/A
1N/Adone:
1N/A if (rgbUnboundData != NULL)
1N/A Tspi_Context_FreeMemory(hContext, rgbUnboundData);
1N/A Tspi_Context_CloseObject(hContext, hEncData);
1N/A return (rc);
1N/A}
1N/A
1N/Astatic CK_RV
1N/Atoken_create_private_tree(TSS_HCONTEXT hContext, CK_BYTE *pinHash)
1N/A{
1N/A CK_RV rc;
1N/A TSS_RESULT result;
1N/A int ret;
1N/A TSS_FLAG initFlags = TSS_KEY_SIZE_2048 |
2N/A TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE |
2N/A TSS_KEY_MIGRATABLE;
2N/A TSS_UUID mrk_uuid = TSS_UUID_MRK;
2N/A TSS_UUID srk_uuid = TSS_UUID_SRK;
2N/A TSS_HKEY hSRK, hMRK;
1N/A
1N/A if (token_load_srk(hContext, &hSRK))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
2N/A if (load_mrk(hContext, hSRK, &hMRK))
2N/A return (CKR_FUNCTION_FAILED);
2N/A
1N/A /*
1N/A * - create UUID privateRootKeyUUID
2N/A * - register root key as a child of the MRK
1N/A * - store privateRootKeyUUID in users private token space.
1N/A */
2N/A if ((result = tss_generate_key(hContext, initFlags, NULL, hMRK,
1N/A &hPrivateRootKey))) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A if (local_uuid_is_null(&privateRootKeyUUID))
1N/A local_uuid_generate(&privateRootKeyUUID);
1N/A
1N/A result = Tspi_Context_RegisterKey(hContext, hPrivateRootKey,
1N/A TSS_PS_TYPE_USER, privateRootKeyUUID,
2N/A TSS_PS_TYPE_SYSTEM,
2N/A (hMRK == hSRK ? srk_uuid : mrk_uuid));
1N/A
1N/A if (result) {
1N/A local_uuid_clear(&privateRootKeyUUID);
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
1N/A ret = add_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID, &privateRootKeyUUID);
1N/A if (ret) {
2N/A (void) Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, privateRootKeyUUID,
1N/A &hPrivateRootKey);
2N/A
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
2N/A if ((result = Tspi_Key_LoadKey(hPrivateRootKey, hMRK))) {
1N/A stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, hPrivateRootKey);
1N/A
1N/A (void) remove_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID);
1N/A local_uuid_clear(&privateRootKeyUUID);
1N/A
1N/A hPrivateRootKey = NULL_HKEY;
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
1N/A
1N/A /* generate the private leaf key */
1N/A if ((rc = token_generate_leaf_key(hContext,
1N/A TPMTOK_PRIVATE_LEAF_KEY,
1N/A pinHash, &hPrivateLeafKey))) {
2N/A goto cleanup;
1N/A }
1N/A
1N/A if ((result = Tspi_Key_LoadKey(hPrivateLeafKey, hPrivateRootKey))) {
1N/A stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A
1N/A (void) Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, privateLeafKeyUUID,
1N/A &hPrivateLeafKey);
1N/A (void) remove_uuid(TPMTOK_PRIVATE_LEAF_KEY_ID);
1N/A local_uuid_clear(&privateLeafKeyUUID);
1N/A
1N/A (void) Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, privateRootKeyUUID,
1N/A &hPrivateRootKey);
1N/A (void) remove_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID);
1N/A local_uuid_clear(&privateRootKeyUUID);
1N/A
1N/A Tspi_Context_CloseObject(hContext, hPrivateRootKey);
1N/A hPrivateRootKey = NULL_HKEY;
1N/A
1N/A Tspi_Context_CloseObject(hContext, hPrivateLeafKey);
1N/A hPrivateRootKey = NULL_HKEY;
1N/A
2N/A rc = CKR_FUNCTION_FAILED;
1N/A }
2N/Acleanup:
2N/A Tspi_Key_UnloadKey(hMRK);
2N/A Tspi_Context_CloseObject(hContext, hMRK);
1N/A return (rc);
1N/A}
1N/A
1N/Astatic CK_RV
1N/Atoken_create_public_tree(TSS_HCONTEXT hContext, CK_BYTE *pinHash)
1N/A{
1N/A CK_RV rc;
1N/A TSS_RESULT result;
1N/A int ret;
1N/A TSS_FLAG initFlags = TSS_KEY_SIZE_2048 |
2N/A TSS_KEY_NO_AUTHORIZATION | TSS_KEY_MIGRATABLE |
2N/A TSS_KEY_TYPE_STORAGE;
2N/A TSS_UUID mrk_uuid = TSS_UUID_MRK;
1N/A TSS_UUID srk_uuid = TSS_UUID_SRK;
2N/A TSS_HKEY hSRK, hMRK;
1N/A
1N/A if (token_load_srk(hContext, &hSRK))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
2N/A if (load_mrk(hContext, hSRK, &hMRK))
2N/A return (CKR_FUNCTION_FAILED);
2N/A
1N/A /*
2N/A * - create publicRootKeyUUID.
2N/A * - register the key under the system MRK.
1N/A * - store publicRootKeyUUID in users private token space.
1N/A */
2N/A if ((result = tss_generate_key(hContext, initFlags, NULL, hMRK,
1N/A &hPublicRootKey))) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A if (local_uuid_is_null(&publicRootKeyUUID))
1N/A local_uuid_generate(&publicRootKeyUUID);
1N/A
1N/A result = Tspi_Context_RegisterKey(hContext, hPublicRootKey,
1N/A TSS_PS_TYPE_USER, publicRootKeyUUID,
2N/A TSS_PS_TYPE_SYSTEM,
2N/A (hMRK == hSRK ? srk_uuid : mrk_uuid));
1N/A
1N/A if (result) {
1N/A local_uuid_clear(&publicRootKeyUUID);
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
1N/A ret = add_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID, &publicRootKeyUUID);
1N/A if (ret) {
2N/A (void) Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, publicRootKeyUUID,
1N/A &hPublicRootKey);
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
1N/A /* Load the newly created publicRootKey into the TPM using the SRK */
2N/A if ((result = Tspi_Key_LoadKey(hPublicRootKey, hMRK))) {
1N/A stlogit("Tspi_Key_LoadKey: 0x%x - %s", result,
1N/A Trspi_Error_String(result));
1N/A Tspi_Context_CloseObject(hContext, hPublicRootKey);
1N/A hPublicRootKey = NULL_HKEY;
2N/A
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
1N/A /* create the SO's leaf key */
1N/A if ((rc = token_generate_leaf_key(hContext, TPMTOK_PUBLIC_LEAF_KEY,
1N/A pinHash, &hPublicLeafKey))) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
1N/A }
1N/A
1N/A if ((result = Tspi_Key_LoadKey(hPublicLeafKey, hPublicRootKey))) {
1N/A stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A
1N/A /* Unregister keys and clear UUIDs */
1N/A (void) Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, publicLeafKeyUUID,
1N/A &hPublicLeafKey);
1N/A (void) remove_uuid(TPMTOK_PUBLIC_LEAF_KEY_ID);
1N/A
1N/A (void) Tspi_Context_UnregisterKey(hContext,
1N/A TSS_PS_TYPE_USER, publicRootKeyUUID,
1N/A &hPublicRootKey);
1N/A (void) remove_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID);
1N/A
1N/A Tspi_Context_CloseObject(hContext, hPublicRootKey);
1N/A hPublicRootKey = NULL_HKEY;
1N/A
1N/A Tspi_Context_CloseObject(hContext, hPublicLeafKey);
1N/A hPublicLeafKey = NULL_HKEY;
1N/A
2N/A rc = CKR_FUNCTION_FAILED;
1N/A }
1N/A
2N/Acleanup:
2N/A Tspi_Key_UnloadKey(hMRK);
2N/A Tspi_Context_CloseObject(hContext, hMRK);
1N/A return (rc);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_login(
1N/A TSS_HCONTEXT hContext,
1N/A CK_USER_TYPE userType,
1N/A CK_CHAR_PTR pPin,
1N/A CK_ULONG ulPinLen)
1N/A{
1N/A CK_RV rc;
1N/A CK_BYTE hash_sha[SHA1_DIGEST_LENGTH];
1N/A TSS_RESULT result;
2N/A TSS_HKEY hSRK, hMRK;
2N/A
2N/A if ((rc = compute_sha(pPin, ulPinLen, hash_sha)))
2N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A /* Make sure the SRK is loaded into the TPM */
2N/A if ((result = token_load_srk(hContext, &hSRK)))
1N/A return (CKR_FUNCTION_FAILED);
2N/A
2N/A if ((result = load_mrk(hContext, hSRK, &hMRK)))
2N/A return (result);
1N/A
1N/A if (userType == CKU_USER) {
1N/A /*
1N/A * If the public root key doesn't exist yet,
1N/A * the SO hasn't init'd the token.
1N/A */
1N/A if ((result = token_load_public_root_key(hContext))) {
1N/A if (result == TPM_E_DECRYPT_ERROR) {
2N/A rc = CKR_USER_PIN_NOT_INITIALIZED;
2N/A goto cleanup;
1N/A }
1N/A }
1N/A
1N/A /*
1N/A * - find privateRootKeyUUID
1N/A * - load by UUID (SRK parent)
1N/A */
1N/A if (local_uuid_is_null(&privateRootKeyUUID) &&
1N/A find_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID,
1N/A &privateRootKeyUUID)) {
1N/A if (memcmp(hash_sha,
1N/A default_user_pin_sha,
1N/A SHA1_DIGEST_LENGTH))
1N/A return (CKR_PIN_INCORRECT);
1N/A
1N/A not_initialized = 1;
2N/A rc = CKR_OK;
2N/A goto cleanup;
1N/A }
1N/A
2N/A if ((rc = verify_user_pin(hContext, hash_sha)))
2N/A goto cleanup;
1N/A
1N/A (void) memcpy(current_user_pin_sha, hash_sha,
1N/A SHA1_DIGEST_LENGTH);
1N/A
1N/A rc = load_private_token_objects(hContext);
1N/A if (rc == CKR_OK) {
1N/A (void) XProcLock(xproclock);
1N/A global_shm->priv_loaded = TRUE;
1N/A (void) XProcUnLock(xproclock);
1N/A }
1N/A } else {
1N/A /*
1N/A * SO login logic:
1N/A *
1N/A * - find publicRootKey UUID
2N/A * - load by UUID wrap with MRK from above
1N/A */
1N/A if (local_uuid_is_null(&publicRootKeyUUID) &&
1N/A find_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID,
1N/A &publicRootKeyUUID)) {
1N/A if (memcmp(hash_sha,
1N/A default_so_pin_sha,
1N/A SHA1_DIGEST_LENGTH))
1N/A return (CKR_PIN_INCORRECT);
1N/A
1N/A not_initialized = 1;
2N/A rc = CKR_OK;
2N/A goto cleanup;
1N/A }
1N/A if (hPublicRootKey == NULL_HKEY) {
1N/A result = tss_find_and_load_key(
1N/A hContext,
1N/A TPMTOK_PUBLIC_ROOT_KEY_ID,
2N/A &publicRootKeyUUID, hMRK, NULL,
1N/A &hPublicRootKey);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A }
1N/A
1N/A /* find, load the public leaf key */
1N/A if (hPublicLeafKey == NULL_HKEY) {
1N/A result = tss_find_and_load_key(
1N/A hContext,
1N/A TPMTOK_PUBLIC_LEAF_KEY_ID,
1N/A &publicLeafKeyUUID, hPublicRootKey, hash_sha,
1N/A &hPublicLeafKey);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A }
1N/A
2N/A if ((rc = token_verify_pin(hContext, hPublicLeafKey)))
2N/A goto cleanup;
1N/A
1N/A (void) memcpy(current_so_pin_sha, hash_sha, SHA1_DIGEST_LENGTH);
1N/A }
1N/A
2N/Acleanup:
2N/A Tspi_Key_UnloadKey(hMRK);
2N/A Tspi_Context_CloseObject(hContext, hMRK);
1N/A return (rc);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_logout(TSS_HCONTEXT hContext)
1N/A{
1N/A if (hPrivateLeafKey != NULL_HKEY) {
1N/A Tspi_Key_UnloadKey(hPrivateLeafKey);
1N/A hPrivateLeafKey = NULL_HKEY;
1N/A } else if (hPublicLeafKey != NULL_HKEY) {
1N/A Tspi_Key_UnloadKey(hPublicLeafKey);
1N/A hPublicLeafKey = NULL_HKEY;
1N/A }
1N/A
1N/A local_uuid_clear(&publicRootKeyUUID);
1N/A local_uuid_clear(&publicLeafKeyUUID);
1N/A local_uuid_clear(&privateRootKeyUUID);
1N/A local_uuid_clear(&privateLeafKeyUUID);
1N/A
1N/A (void) memset(current_so_pin_sha, 0, SHA1_DIGEST_LENGTH);
1N/A (void) memset(current_user_pin_sha, 0, SHA1_DIGEST_LENGTH);
1N/A
1N/A (void) object_mgr_purge_private_token_objects(hContext);
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/A/*ARGSUSED*/
1N/ACK_RV
1N/Atoken_specific_init_pin(TSS_HCONTEXT hContext,
1N/A CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
1N/A{
1N/A /*
1N/A * Since the SO must log in before calling C_InitPIN, we will
1N/A * be able to return (CKR_OK) automatically here.
1N/A * This is because the USER key structure is created at the
1N/A * time of her first login, not at C_InitPIN time.
1N/A */
1N/A return (CKR_OK);
1N/A}
1N/A
1N/Astatic CK_RV
1N/Acheck_pin_properties(CK_USER_TYPE userType, CK_BYTE *pinHash,
1N/A CK_ULONG ulPinLen)
1N/A{
1N/A /* make sure the new PIN is different */
1N/A if (userType == CKU_USER) {
1N/A if (!memcmp(pinHash, default_user_pin_sha,
1N/A SHA1_DIGEST_LENGTH)) {
1N/A LogError1("new PIN must not be the default");
1N/A return (CKR_PIN_INVALID);
1N/A }
1N/A } else {
1N/A if (!memcmp(pinHash, default_so_pin_sha,
1N/A SHA1_DIGEST_LENGTH)) {
1N/A LogError1("new PIN must not be the default");
1N/A return (CKR_PIN_INVALID);
1N/A }
1N/A }
1N/A
1N/A if (ulPinLen > MAX_PIN_LEN || ulPinLen < MIN_PIN_LEN) {
1N/A LogError1("New PIN is out of size range");
1N/A return (CKR_PIN_LEN_RANGE);
1N/A }
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/A/*
1N/A * This function is called from set_pin only, where a non-logged-in public
1N/A * session can provide the user pin which must be verified. This function
1N/A * assumes that the pin has already been set once, so there's no migration
1N/A * path option or checking of the default user pin.
1N/A */
1N/Astatic CK_RV
1N/Averify_user_pin(TSS_HCONTEXT hContext, CK_BYTE *hash_sha)
1N/A{
1N/A CK_RV rc;
1N/A TSS_RESULT result;
1N/A TSS_HKEY hSRK;
2N/A TSS_HKEY hMRK;
1N/A
1N/A if (token_load_srk(hContext, &hSRK))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
2N/A if ((result = load_mrk(hContext, hSRK, &hMRK)))
2N/A return (result);
2N/A
1N/A /*
1N/A * Verify the user by loading the privateLeafKey
1N/A * into the TPM (if it's not already) and then
1N/A * call the verify_pin operation.
1N/A *
1N/A * The hashed PIN is assigned to the private leaf key.
1N/A * If it is incorrect (not the same as the one originally
1N/A * used when the key was created), the verify operation
1N/A * will fail.
1N/A */
1N/A if (hPrivateRootKey == NULL_HKEY) {
1N/A result = tss_find_and_load_key(
1N/A hContext,
1N/A TPMTOK_PRIVATE_ROOT_KEY_ID,
2N/A &privateRootKeyUUID, hMRK, NULL, &hPrivateRootKey);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A }
1N/A
1N/A if (hPrivateLeafKey == NULL_HKEY) {
1N/A result = tss_find_and_load_key(
1N/A hContext,
1N/A TPMTOK_PRIVATE_LEAF_KEY_ID,
1N/A &privateLeafKeyUUID, hPrivateRootKey, hash_sha,
1N/A &hPrivateLeafKey);
1N/A
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A }
1N/A
1N/A /*
1N/A * Verify that the PIN is correct by attempting to wrap/unwrap some
1N/A * random data.
1N/A */
2N/A rc = token_verify_pin(hContext, hPrivateLeafKey);
2N/Acleanup:
2N/A Tspi_Key_UnloadKey(hMRK);
2N/A Tspi_Context_CloseObject(hContext, hMRK);
2N/A return (rc);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_set_pin(ST_SESSION_HANDLE session,
1N/A CK_CHAR_PTR pOldPin, CK_ULONG ulOldPinLen,
1N/A CK_CHAR_PTR pNewPin, CK_ULONG ulNewPinLen)
1N/A{
1N/A SESSION *sess = session_mgr_find(session.sessionh);
1N/A CK_BYTE oldpin_hash[SHA1_DIGEST_LENGTH];
1N/A CK_BYTE newpin_hash[SHA1_DIGEST_LENGTH];
1N/A CK_RV rc;
1N/A TSS_HKEY hSRK;
1N/A
1N/A if (!sess) {
1N/A return (CKR_SESSION_HANDLE_INVALID);
1N/A }
1N/A
1N/A if ((rc = compute_sha(pOldPin, ulOldPinLen, oldpin_hash))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A if ((rc = compute_sha(pNewPin, ulNewPinLen, newpin_hash))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if (token_load_srk(sess->hContext, &hSRK)) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /*
1N/A * From the PKCS#11 2.20 spec: "C_SetPIN modifies the PIN of
1N/A * the user that is currently logged in, or the CKU_USER PIN
1N/A * if the session is not logged in."
1N/A * A non R/W session fails with CKR_SESSION_READ_ONLY.
1N/A */
1N/A if (sess->session_info.state == CKS_RW_USER_FUNCTIONS ||
1N/A sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
1N/A if (not_initialized) {
1N/A if (memcmp(oldpin_hash, default_user_pin_sha,
1N/A SHA1_DIGEST_LENGTH)) {
1N/A return (CKR_PIN_INCORRECT);
1N/A }
1N/A
1N/A if ((rc = check_pin_properties(CKU_USER, newpin_hash,
1N/A ulNewPinLen))) {
1N/A return (rc);
1N/A }
1N/A
1N/A if ((rc = token_create_private_tree(sess->hContext,
1N/A newpin_hash))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A nv_token_data->token_info.flags &=
1N/A ~(CKF_USER_PIN_TO_BE_CHANGED);
1N/A nv_token_data->token_info.flags |=
1N/A CKF_USER_PIN_INITIALIZED;
1N/A
1N/A nv_token_data->token_info.flags &=
1N/A ~(CKF_USER_PIN_TO_BE_CHANGED);
1N/A nv_token_data->token_info.flags |=
1N/A CKF_USER_PIN_INITIALIZED;
1N/A
1N/A return (save_token_data(nv_token_data));
1N/A }
1N/A
1N/A if (sess->session_info.state == CKS_RW_USER_FUNCTIONS) {
1N/A /* if we're already logged in, just verify the hash */
1N/A if (memcmp(current_user_pin_sha, oldpin_hash,
1N/A SHA1_DIGEST_LENGTH)) {
1N/A return (CKR_PIN_INCORRECT);
1N/A }
1N/A } else {
1N/A if ((rc = verify_user_pin(sess->hContext,
1N/A oldpin_hash))) {
1N/A return (rc);
1N/A }
1N/A }
1N/A
1N/A if ((rc = check_pin_properties(CKU_USER, newpin_hash,
1N/A ulNewPinLen)))
1N/A return (rc);
1N/A
1N/A /* change the auth on the TSS object */
1N/A if (tss_change_auth(sess->hContext,
1N/A hPrivateLeafKey, hPrivateRootKey,
1N/A privateLeafKeyUUID, privateRootKeyUUID,
1N/A newpin_hash))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A } else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
1N/A if (not_initialized) {
1N/A if (memcmp(default_so_pin_sha, oldpin_hash,
1N/A SHA1_DIGEST_LENGTH))
1N/A return (CKR_PIN_INCORRECT);
1N/A
1N/A if ((rc = check_pin_properties(CKU_SO,
1N/A newpin_hash, ulNewPinLen)))
1N/A return (rc);
1N/A
1N/A if ((rc = token_create_public_tree(sess->hContext,
1N/A newpin_hash)))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A nv_token_data->token_info.flags &=
1N/A ~(CKF_SO_PIN_TO_BE_CHANGED);
1N/A
1N/A return (save_token_data(nv_token_data));
1N/A }
1N/A
1N/A if (memcmp(current_so_pin_sha, oldpin_hash,
1N/A SHA1_DIGEST_LENGTH))
1N/A return (CKR_PIN_INCORRECT);
1N/A
1N/A if ((rc = check_pin_properties(CKU_SO, newpin_hash,
1N/A ulNewPinLen)))
1N/A return (rc);
1N/A
1N/A /* change auth on the SO's leaf key */
1N/A if (tss_change_auth(sess->hContext,
1N/A hPublicLeafKey, hPublicRootKey,
1N/A publicLeafKeyUUID, publicRootKeyUUID,
1N/A newpin_hash))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A } else {
1N/A rc = CKR_SESSION_READ_ONLY;
1N/A }
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/A/* only called at token init time */
1N/ACK_RV
1N/Atoken_specific_verify_so_pin(TSS_HCONTEXT hContext, CK_CHAR_PTR pPin,
1N/A CK_ULONG ulPinLen)
1N/A{
1N/A CK_BYTE hash_sha[SHA1_DIGEST_LENGTH];
1N/A CK_RV rc;
1N/A TSS_RESULT result;
2N/A TSS_HKEY hSRK, hMRK = NULL;
1N/A
1N/A if ((rc = compute_sha(pPin, ulPinLen, hash_sha))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A if ((rc = token_load_srk(hContext, &hSRK))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A /*
1N/A * TRYME INSTEAD:
1N/A * - find publicRootKeyUUID
2N/A * - Load publicRootKey by UUID (MRK parent)
1N/A * - find publicLeafKeyUUID
1N/A * - Load publicLeafKey by UUID (publicRootKey parent)
1N/A * - set password policy on publicLeafKey
1N/A */
1N/A if (local_uuid_is_null(&publicRootKeyUUID) &&
1N/A find_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID, &publicRootKeyUUID)) {
1N/A /*
1N/A * The SO hasn't set her PIN yet, compare the
1N/A * login pin with the hard-coded value.
1N/A */
1N/A if (memcmp(default_so_pin_sha, hash_sha,
1N/A SHA1_DIGEST_LENGTH)) {
1N/A return (CKR_PIN_INCORRECT);
1N/A }
1N/A return (CKR_OK);
1N/A }
1N/A
1N/A result = Tspi_Context_GetKeyByUUID(hContext,
1N/A TSS_PS_TYPE_USER, publicRootKeyUUID, &hPublicRootKey);
1N/A
1N/A if (result)
1N/A return (CKR_FUNCTION_FAILED);
1N/A
2N/A if ((rc = load_mrk(hContext, hSRK, &hMRK)))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
2N/A result = Tspi_Key_LoadKey(hPublicRootKey, hMRK);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
2N/A
1N/A if (local_uuid_is_null(&publicLeafKeyUUID) &&
2N/A find_uuid(TPMTOK_PUBLIC_LEAF_KEY_ID, &publicLeafKeyUUID)) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A
1N/A result = Tspi_Context_GetKeyByUUID(hContext,
1N/A TSS_PS_TYPE_USER, publicLeafKeyUUID, &hPublicLeafKey);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A
1N/A result = tss_assign_secret_key_policy(hContext, TSS_POLICY_USAGE,
1N/A hPublicLeafKey, hash_sha);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A
1N/A result = Tspi_Key_LoadKey(hPublicLeafKey, hPublicRootKey);
2N/A if (result) {
2N/A rc = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
1N/A
1N/A /* If the hash given is wrong, the verify will fail */
2N/A rc = token_verify_pin(hContext, hPublicLeafKey);
2N/A
2N/Acleanup:
2N/A Tspi_Key_UnloadKey(hMRK);
2N/A Tspi_Context_CloseObject(hContext, hMRK);
2N/A
2N/A return (rc);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_final(TSS_HCONTEXT hContext)
1N/A{
1N/A if (hPublicRootKey != NULL_HKEY) {
1N/A Tspi_Context_CloseObject(hContext, hPublicRootKey);
1N/A hPublicRootKey = NULL_HKEY;
1N/A }
1N/A if (hPublicLeafKey != NULL_HKEY) {
1N/A Tspi_Context_CloseObject(hContext, hPublicLeafKey);
1N/A hPublicLeafKey = NULL_HKEY;
1N/A }
1N/A if (hPrivateRootKey != NULL_HKEY) {
1N/A Tspi_Context_CloseObject(hContext, hPrivateRootKey);
1N/A hPrivateRootKey = NULL_HKEY;
1N/A }
1N/A if (hPrivateLeafKey != NULL_HKEY) {
1N/A Tspi_Context_CloseObject(hContext, hPrivateLeafKey);
1N/A hPrivateLeafKey = NULL_HKEY;
1N/A }
1N/A return (CKR_OK);
1N/A}
1N/A
1N/A/*
1N/A * Wrap the 20 bytes of auth data and store in an attribute of the two
1N/A * keys.
1N/A */
1N/Astatic CK_RV
1N/Atoken_wrap_auth_data(TSS_HCONTEXT hContext,
1N/A CK_BYTE *authData, TEMPLATE *publ_tmpl,
1N/A TEMPLATE *priv_tmpl)
1N/A{
1N/A CK_RV rc;
1N/A CK_ATTRIBUTE *new_attr;
1N/A
1N/A TSS_RESULT ret;
1N/A TSS_HKEY hParentKey;
1N/A TSS_HENCDATA hEncData;
1N/A BYTE *blob;
1N/A UINT32 blob_size;
1N/A
1N/A if ((hPrivateLeafKey == NULL_HKEY) && (hPublicLeafKey == NULL_HKEY)) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A } else if (hPublicLeafKey != NULL_HKEY) {
1N/A hParentKey = hPublicLeafKey;
1N/A } else {
1N/A hParentKey = hPrivateLeafKey;
1N/A }
1N/A
1N/A /* create the encrypted data object */
1N/A if ((ret = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A ret, Trspi_Error_String(ret));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((ret = Tspi_Data_Bind(hEncData, hParentKey, SHA1_DIGEST_LENGTH,
1N/A authData))) {
1N/A stlogit("Tspi_Data_Bind: 0x%0x - %s",
1N/A ret, Trspi_Error_String(ret));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* pull the encrypted data out of the encrypted data object */
1N/A if ((ret = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
1N/A TSS_TSPATTRIB_ENCDATABLOB_BLOB, &blob_size, &blob))) {
1N/A stlogit("Tspi_SetAttribData: 0x%0x - %s",
1N/A ret, Trspi_Error_String(ret));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((rc = build_attribute(CKA_ENC_AUTHDATA, blob, blob_size,
1N/A &new_attr))) {
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(publ_tmpl, new_attr);
1N/A
1N/A if ((rc = build_attribute(CKA_ENC_AUTHDATA, blob,
1N/A blob_size, &new_attr))) {
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(priv_tmpl, new_attr);
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/Astatic CK_RV
1N/Atoken_unwrap_auth_data(TSS_HCONTEXT hContext, CK_BYTE *encAuthData,
1N/A CK_ULONG encAuthDataLen, TSS_HKEY hKey,
1N/A BYTE **authData)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HENCDATA hEncData;
1N/A BYTE *buf;
1N/A UINT32 buf_size;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_SetAttribData(hEncData,
1N/A TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB,
1N/A encAuthDataLen, encAuthData))) {
1N/A stlogit("Tspi_SetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* unbind the data, receiving the plaintext back */
1N/A if ((result = Tspi_Data_Unbind(hEncData, hKey, &buf_size, &buf))) {
1N/A stlogit("Tspi_Data_Unbind: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if (buf_size != SHA1_DIGEST_LENGTH) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A *authData = buf;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_generate_keypair(
1N/A TSS_HCONTEXT hContext,
1N/A TEMPLATE *publ_tmpl,
1N/A TEMPLATE *priv_tmpl)
1N/A{
1N/A CK_ATTRIBUTE *attr = NULL;
1N/A CK_ULONG mod_bits = 0;
1N/A CK_BBOOL flag;
1N/A CK_RV rc;
1N/A
1N/A TSS_FLAG initFlags = 0;
1N/A BYTE authHash[SHA1_DIGEST_LENGTH];
1N/A BYTE *authData = NULL;
1N/A TSS_HKEY hKey = NULL_HKEY;
1N/A TSS_HKEY hParentKey = NULL_HKEY;
1N/A TSS_RESULT result;
1N/A UINT32 ulBlobLen;
1N/A BYTE *rgbBlob;
1N/A
1N/A /* Make sure the public exponent is usable */
1N/A if ((util_check_public_exponent(publ_tmpl))) {
1N/A return (CKR_TEMPLATE_INCONSISTENT);
1N/A }
1N/A
1N/A flag = template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr);
1N/A if (!flag) {
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A mod_bits = *(CK_ULONG *)attr->pValue;
1N/A
1N/A if ((initFlags = util_get_keysize_flag(mod_bits)) == 0) {
1N/A return (CKR_KEY_SIZE_RANGE);
1N/A }
1N/A
1N/A /*
1N/A * If we're not logged in, hPrivateLeafKey and hPublicLeafKey
1N/A * should be NULL.
1N/A */
1N/A if ((hPrivateLeafKey == NULL_HKEY) &&
1N/A (hPublicLeafKey == NULL_HKEY)) {
1N/A /* public session, wrap key with the PRK */
1N/A initFlags |= TSS_KEY_TYPE_LEGACY |
1N/A TSS_KEY_NO_AUTHORIZATION | TSS_KEY_MIGRATABLE;
1N/A
1N/A if ((result = token_load_public_root_key(hContext))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A hParentKey = hPublicRootKey;
1N/A } else if (hPrivateLeafKey != NULL_HKEY) {
1N/A /* logged in USER session */
1N/A initFlags |= TSS_KEY_TYPE_LEGACY |
1N/A TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE;
1N/A
1N/A /* get a random SHA1 hash for the auth data */
1N/A if ((rc = token_rng(hContext, authHash, SHA1_DIGEST_LENGTH))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A authData = authHash;
1N/A hParentKey = hPrivateRootKey;
1N/A } else {
1N/A /* logged in SO session */
1N/A initFlags |= TSS_KEY_TYPE_LEGACY |
1N/A TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE;
1N/A
1N/A /* get a random SHA1 hash for the auth data */
1N/A if ((rc = token_rng(hContext, authHash, SHA1_DIGEST_LENGTH))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A authData = authHash;
1N/A hParentKey = hPublicRootKey;
1N/A }
1N/A
1N/A if ((result = tss_generate_key(hContext, initFlags, authData,
1N/A hParentKey, &hKey))) {
1N/A return (result);
1N/A }
1N/A
1N/A if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
1N/A TSS_TSPATTRIB_KEYBLOB_BLOB, &ulBlobLen, &rgbBlob))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob,
1N/A ulBlobLen, &attr))) {
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(priv_tmpl, attr);
1N/A if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob,
1N/A ulBlobLen, &attr))) {
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(publ_tmpl, attr);
1N/A
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A
1N/A /* grab the public key to put into the public key object */
1N/A if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &ulBlobLen, &rgbBlob))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A
1N/A /* add the public key blob to the object template */
1N/A if ((rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr))) {
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(publ_tmpl, attr);
1N/A
1N/A /* add the public key blob to the object template */
1N/A if ((rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr))) {
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A return (rc);
1N/A }
1N/A (void) template_update_attribute(priv_tmpl, attr);
1N/A Tspi_Context_FreeMemory(hContext, rgbBlob);
1N/A
1N/A /* wrap the authdata and put it into an object */
1N/A if (authData != NULL) {
1N/A rc = token_wrap_auth_data(hContext, authData, publ_tmpl,
1N/A priv_tmpl);
1N/A }
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/Astatic CK_RV
1N/Atoken_rsa_load_key(
1N/A TSS_HCONTEXT hContext,
1N/A OBJECT *key_obj,
1N/A TSS_HKEY *phKey)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HPOLICY hPolicy = NULL_HPOLICY;
1N/A TSS_HKEY hParentKey;
1N/A BYTE *authData = NULL;
1N/A CK_ATTRIBUTE *attr;
1N/A CK_RV rc;
1N/A CK_OBJECT_HANDLE handle;
1N/A CK_ULONG class;
1N/A
1N/A if (hPrivateLeafKey != NULL_HKEY) {
1N/A hParentKey = hPrivateRootKey;
1N/A } else {
1N/A if ((result = token_load_public_root_key(hContext)))
1N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A hParentKey = hPublicRootKey;
1N/A }
1N/A
1N/A *phKey = NULL;
1N/A if (template_attribute_find(key_obj->template, CKA_CLASS,
1N/A &attr) == FALSE) {
1N/A return (CKR_TEMPLATE_INCOMPLETE);
1N/A }
1N/A class = *((CK_ULONG *)attr->pValue);
1N/A
1N/A rc = template_attribute_find(key_obj->template,
1N/A CKA_IBM_OPAQUE, &attr);
1N/A /*
1N/A * A public key cannot use the OPAQUE data attribute so they
1N/A * must be created in software. A private key may not yet
1N/A * have its "opaque" data defined and needs to be created
1N/A * and loaded so it can be used inside the TPM.
1N/A */
1N/A if (class == CKO_PUBLIC_KEY || rc == FALSE) {
1N/A rc = object_mgr_find_in_map2(hContext, key_obj, &handle);
1N/A if (rc != CKR_OK)
1N/A return (CKR_FUNCTION_FAILED);
1N/A
1N/A if ((rc = token_load_key(hContext,
1N/A handle, hParentKey, NULL, phKey))) {
1N/A return (rc);
1N/A }
1N/A }
1N/A /*
1N/A * If this is a private key, get the blob and load it in the TPM.
1N/A * If it is public, the key is already loaded in software.
1N/A */
1N/A if (class == CKO_PRIVATE_KEY) {
1N/A /* If we already have a handle, just load it */
1N/A if (*phKey != NULL) {
1N/A result = Tspi_Key_LoadKey(*phKey, hParentKey);
1N/A if (result) {
1N/A stlogit("Tspi_Context_LoadKeyByBlob: "
1N/A "0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A } else {
1N/A /* try again to get the CKA_IBM_OPAQUE attr */
1N/A if ((rc = template_attribute_find(key_obj->template,
1N/A CKA_IBM_OPAQUE, &attr)) == FALSE) {
1N/A return (rc);
1N/A }
1N/A if ((result = Tspi_Context_LoadKeyByBlob(hContext,
1N/A hParentKey, attr->ulValueLen, attr->pValue,
1N/A phKey))) {
1N/A stlogit("Tspi_Context_LoadKeyByBlob: "
1N/A "0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A }
1N/A }
1N/A
1N/A /* auth data may be required */
1N/A if (template_attribute_find(key_obj->template, CKA_ENC_AUTHDATA,
1N/A &attr) == TRUE && attr) {
1N/A if ((hPrivateLeafKey == NULL_HKEY) &&
1N/A (hPublicLeafKey == NULL_HKEY)) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A } else if (hPublicLeafKey != NULL_HKEY) {
1N/A hParentKey = hPublicLeafKey;
1N/A } else {
1N/A hParentKey = hPrivateLeafKey;
1N/A }
1N/A
1N/A if ((result = token_unwrap_auth_data(hContext,
1N/A attr->pValue, attr->ulValueLen,
1N/A hParentKey, &authData))) {
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_GetPolicyObject(*phKey,
1N/A TSS_POLICY_USAGE, &hPolicy))) {
1N/A stlogit("Tspi_GetPolicyObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /*
1N/A * If the policy handle returned is the same as the
1N/A * context's default policy, then a new policy must
1N/A * be created and assigned to the key. Otherwise, just set the
1N/A * secret in the policy.
1N/A */
1N/A if (hPolicy == hDefaultPolicy) {
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
1N/A &hPolicy))) {
1N/A stlogit("Tspi_Context_CreateObject: "
1N/A "0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_Policy_SetSecret(hPolicy,
1N/A TSS_SECRET_MODE_SHA1,
1N/A SHA1_DIGEST_LENGTH, authData))) {
1N/A stlogit("Tspi_Policy_SetSecret: "
1N/A "0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_Policy_AssignToObject(hPolicy,
1N/A *phKey))) {
1N/A stlogit("Tspi_Policy_AssignToObject: "
1N/A "0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A } else if ((result = Tspi_Policy_SetSecret(hPolicy,
1N/A TSS_SECRET_MODE_SHA1, SHA1_DIGEST_LENGTH, authData))) {
1N/A stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A Tspi_Context_FreeMemory(hContext, authData);
1N/A }
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Atpm_decrypt_data(
1N/A TSS_HCONTEXT hContext,
1N/A TSS_HKEY hKey,
1N/A CK_BYTE * in_data,
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE * out_data,
1N/A CK_ULONG * out_data_len)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HENCDATA hEncData = NULL_HENCDATA;
1N/A UINT32 buf_size = 0, modLen;
1N/A BYTE *buf = NULL, *modulus = NULL;
1N/A CK_ULONG chunklen, remain, outlen;
1N/A
1N/A /* push the data into the encrypted data object */
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /*
1N/A * Figure out the modulus size so we can break the data
1N/A * into smaller chunks if necessary.
1N/A */
1N/A if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modLen, &modulus))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A /* we don't need the actual modulus */
1N/A Tspi_Context_FreeMemory(hContext, modulus);
1N/A
1N/A chunklen = (in_data_len > modLen ? modLen : in_data_len);
1N/A remain = in_data_len;
1N/A outlen = 0;
1N/A
1N/A while (remain > 0) {
1N/A if ((result = Tspi_SetAttribData(hEncData,
1N/A TSS_TSPATTRIB_ENCDATA_BLOB,
1N/A TSS_TSPATTRIB_ENCDATABLOB_BLOB,
1N/A chunklen, in_data))) {
1N/A stlogit("Tspi_SetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* unbind the data, receiving the plaintext back */
1N/A if ((result = Tspi_Data_Unbind(hEncData, hKey,
1N/A &buf_size, &buf))) {
1N/A stlogit("Tspi_Data_Unbind: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if (*out_data_len < buf_size + outlen) {
1N/A Tspi_Context_FreeMemory(hContext, buf);
1N/A return (CKR_BUFFER_TOO_SMALL);
1N/A }
1N/A
1N/A (void) memcpy(out_data + outlen, buf, buf_size);
1N/A
1N/A outlen += buf_size;
1N/A in_data += chunklen;
1N/A remain -= chunklen;
1N/A
1N/A Tspi_Context_FreeMemory(hContext, buf);
1N/A if (chunklen > remain)
1N/A chunklen = remain;
1N/A }
1N/A *out_data_len = outlen;
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_decrypt(
1N/A TSS_HCONTEXT hContext,
1N/A CK_BYTE * in_data,
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE * out_data,
1N/A CK_ULONG * out_data_len,
1N/A OBJECT * key_obj)
1N/A{
1N/A CK_RV rc;
1N/A TSS_HKEY hKey;
1N/A
1N/A if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
1N/A return (rc);
1N/A }
1N/A
1N/A rc = tpm_decrypt_data(hContext, hKey, in_data, in_data_len,
1N/A out_data, out_data_len);
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_verify(
1N/A TSS_HCONTEXT hContext,
1N/A CK_BYTE * in_data,
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE * sig,
1N/A CK_ULONG sig_len,
1N/A OBJECT * key_obj)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HHASH hHash;
1N/A TSS_HKEY hKey;
1N/A CK_RV rc;
1N/A
1N/A if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
1N/A return (rc);
1N/A }
1N/A
1N/A /* Create the hash object we'll use to sign */
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &hHash))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* Insert the data into the hash object */
1N/A if ((result = Tspi_Hash_SetHashValue(hHash, in_data_len,
1N/A in_data))) {
1N/A stlogit("Tspi_Hash_SetHashValue: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* Verify */
1N/A result = Tspi_Hash_VerifySignature(hHash, hKey, sig_len, sig);
1N/A if (result != TSS_SUCCESS &&
1N/A TPMTOK_TSS_ERROR_CODE(result) != TSS_E_FAIL) {
1N/A stlogit("Tspi_Hash_VerifySignature: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A }
1N/A
1N/A if (TPMTOK_TSS_ERROR_CODE(result) == TSS_E_FAIL) {
1N/A rc = CKR_SIGNATURE_INVALID;
1N/A } else {
1N/A rc = CKR_OK;
1N/A }
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_sign(
1N/A TSS_HCONTEXT hContext,
1N/A CK_BYTE * in_data,
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE * out_data,
1N/A CK_ULONG * out_data_len,
1N/A OBJECT * key_obj)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HHASH hHash;
1N/A BYTE *sig;
1N/A UINT32 sig_len;
1N/A TSS_HKEY hKey;
1N/A CK_RV rc;
1N/A
1N/A if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
1N/A return (rc);
1N/A }
1N/A
1N/A /* Create the hash object we'll use to sign */
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &hHash))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* Insert the data into the hash object */
1N/A if ((result = Tspi_Hash_SetHashValue(hHash, in_data_len,
1N/A in_data))) {
1N/A stlogit("Tspi_Hash_SetHashValue: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A /* Sign */
1N/A if ((result = Tspi_Hash_Sign(hHash, hKey, &sig_len, &sig))) {
1N/A stlogit("Tspi_Hash_Sign: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_DATA_LEN_RANGE);
1N/A }
1N/A
1N/A if (sig_len > *out_data_len) {
1N/A Tspi_Context_FreeMemory(hContext, sig);
1N/A return (CKR_BUFFER_TOO_SMALL);
1N/A }
1N/A
1N/A (void) memcpy(out_data, sig, sig_len);
1N/A *out_data_len = sig_len;
1N/A Tspi_Context_FreeMemory(hContext, sig);
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Atpm_encrypt_data(
1N/A TSS_HCONTEXT hContext,
1N/A TSS_HKEY hKey,
1N/A CK_BYTE *in_data,
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE *out_data,
1N/A CK_ULONG *out_data_len)
1N/A{
1N/A TSS_RESULT result;
1N/A TSS_HENCDATA hEncData;
1N/A BYTE *dataBlob, *modulus;
1N/A UINT32 dataBlobSize, modLen;
1N/A CK_ULONG chunklen, remain;
1N/A CK_ULONG outlen;
1N/A UINT32 keyusage, scheme, maxsize;
1N/A
1N/A if ((result = Tspi_Context_CreateObject(hContext,
1N/A TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
1N/A stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A /*
1N/A * Figure out the modulus size so we can break the data
1N/A * into smaller chunks if necessary.
1N/A */
1N/A if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modLen, &modulus))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A /* we don't need the actual modulus */
1N/A Tspi_Context_FreeMemory(hContext, modulus);
1N/A
1N/A /*
1N/A * According to TSS spec for Tspi_Data_Bind (4.3.4.21.5),
1N/A * Max input data size varies depending on the key type and
1N/A * encryption scheme.
1N/A */
1N/A if ((result = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_USAGE, &keyusage))) {
1N/A stlogit("Cannot find USAGE: %s\n",
1N/A Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A if ((result = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_ENCSCHEME, &scheme))) {
1N/A stlogit("Cannot find ENCSCHEME: %s\n",
1N/A Trspi_Error_String(result));
1N/A return (result);
1N/A }
1N/A switch (scheme) {
1N/A case TSS_ES_RSAESPKCSV15:
1N/A if (keyusage == TSS_KEYUSAGE_BIND)
1N/A maxsize = 16;
1N/A else /* legacy */
1N/A maxsize = 11;
1N/A break;
1N/A case TSS_ES_RSAESOAEP_SHA1_MGF1:
1N/A maxsize = 47;
1N/A break;
1N/A default:
1N/A maxsize = 0;
1N/A }
1N/A
1N/A modLen -= maxsize;
1N/A
1N/A chunklen = (in_data_len > modLen ? modLen : in_data_len);
1N/A remain = in_data_len;
1N/A outlen = 0;
1N/A while (remain > 0) {
1N/A if ((result = Tspi_Data_Bind(hEncData, hKey,
1N/A chunklen, in_data))) {
1N/A stlogit("Tspi_Data_Bind: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if ((result = Tspi_GetAttribData(hEncData,
1N/A TSS_TSPATTRIB_ENCDATA_BLOB,
1N/A TSS_TSPATTRIB_ENCDATABLOB_BLOB,
1N/A &dataBlobSize, &dataBlob))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if (outlen + dataBlobSize > *out_data_len) {
1N/A Tspi_Context_FreeMemory(hContext, dataBlob);
1N/A return (CKR_DATA_LEN_RANGE);
1N/A }
1N/A
1N/A (void) memcpy(out_data + outlen,
1N/A dataBlob, dataBlobSize);
1N/A
1N/A outlen += dataBlobSize;
1N/A in_data += chunklen;
1N/A remain -= chunklen;
1N/A
1N/A if (chunklen > remain)
1N/A chunklen = remain;
1N/A
1N/A Tspi_Context_FreeMemory(hContext, dataBlob);
1N/A }
1N/A *out_data_len = outlen;
1N/A
1N/A return (CKR_OK);
1N/A}
1N/A
1N/ACK_RV
1N/Atoken_specific_rsa_encrypt(
1N/A TSS_HCONTEXT hContext,
1N/A CK_BYTE * in_data,
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE * out_data,
1N/A CK_ULONG * out_data_len,
1N/A OBJECT * key_obj)
1N/A{
1N/A TSS_HKEY hKey;
1N/A CK_RV rc;
1N/A
1N/A if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
1N/A return (rc);
1N/A }
1N/A
1N/A rc = tpm_encrypt_data(hContext, hKey, in_data, in_data_len,
1N/A out_data, out_data_len);
1N/A
1N/A return (rc);
1N/A}
1N/A
1N/A/*
1N/A * RSA Verify Recover
1N/A *
1N/A * Public key crypto is done in software, not by the TPM.
1N/A * We bypass the TSPI library here in favor of calls directly
1N/A * to OpenSSL because we don't want to add any padding, the in_data (signature)
1N/A * already contains the data stream to be decrypted and is already
1N/A * padded and formatted correctly.
1N/A */
1N/ACK_RV
1N/Atoken_specific_rsa_verify_recover(
1N/A TSS_HCONTEXT hContext,
1N/A CK_BYTE *in_data, /* signature */
1N/A CK_ULONG in_data_len,
1N/A CK_BYTE *out_data, /* decrypted */
1N/A CK_ULONG *out_data_len,
1N/A OBJECT *key_obj)
1N/A{
1N/A TSS_HKEY hKey;
1N/A TSS_RESULT result;
1N/A CK_RV rc;
1N/A BYTE *modulus;
1N/A UINT32 modLen;
1N/A RSA *rsa = NULL;
1N/A uchar_t exp[] = { 0x01, 0x00, 0x01 };
1N/A int sslrv, num;
1N/A BYTE temp[MAX_RSA_KEYLENGTH];
1N/A BYTE outdata[MAX_RSA_KEYLENGTH];
1N/A int i;
1N/A
1N/A if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
1N/A return (rc);
1N/A }
1N/A
1N/A if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
1N/A TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modLen, &modulus))) {
1N/A stlogit("Tspi_GetAttribData: 0x%0x - %s",
1N/A result, Trspi_Error_String(result));
1N/A return (CKR_FUNCTION_FAILED);
1N/A }
1N/A
1N/A if (in_data_len != modLen) {
1N/A rc = CKR_SIGNATURE_LEN_RANGE;
1N/A goto end;
1N/A }
1N/A
1N/A rsa = RSA_new();
1N/A if (rsa == NULL) {
1N/A rc = CKR_HOST_MEMORY;
1N/A goto end;
1N/A }
1N/A
1N/A rsa->n = BN_bin2bn(modulus, modLen, rsa->n);
1N/A rsa->e = BN_bin2bn(exp, sizeof (exp), rsa->e);
1N/A if (rsa->n == NULL || rsa->e == NULL) {
1N/A rc = CKR_HOST_MEMORY;
1N/A goto end;
1N/A }
1N/A
1N/A rsa->flags |= RSA_FLAG_SIGN_VER;
1N/A
1N/A /* use RSA_NO_PADDING because the data is already padded (PKCS1) */
1N/A sslrv = RSA_public_encrypt(in_data_len, in_data, outdata,
1N/A rsa, RSA_NO_PADDING);
1N/A if (sslrv == -1) {
1N/A rc = CKR_FUNCTION_FAILED;
1N/A goto end;
1N/A }
1N/A
1N/A /* Strip leading 0's before stripping the padding */
1N/A for (i = 0; i < sslrv; i++)
1N/A if (outdata[i] != 0)
1N/A break;
1N/A
1N/A num = BN_num_bytes(rsa->n);
1N/A
1N/A /* Use OpenSSL function for stripping PKCS#1 padding */
1N/A sslrv = RSA_padding_check_PKCS1_type_1(temp, sizeof (temp),
1N/A &outdata[i], sslrv - i, num);
1N/A
1N/A if (sslrv < 0) {
1N/A rc = CKR_FUNCTION_FAILED;
1N/A goto end;
1N/A }
1N/A
1N/A if (*out_data_len < sslrv) {
1N/A rc = CKR_BUFFER_TOO_SMALL;
1N/A *out_data_len = 0;
1N/A goto end;
1N/A }
1N/A
1N/A /* The return code indicates the number of bytes remaining */
1N/A (void) memcpy(out_data, temp, sslrv);
1N/A *out_data_len = sslrv;
1N/Aend:
1N/A Tspi_Context_FreeMemory(hContext, modulus);
1N/A if (rsa)
1N/A RSA_free(rsa);
1N/A
1N/A return (rc);
1N/A}