blob: eb539f2da2290bf5c6760949cb765984ced20df4 [file] [log] [blame]
/*
* The Initial Developer of the Original Code is International
* Business Machines Corporation. Portions created by IBM
* Corporation are Copyright (C) 2005 International Business
* Machines Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Common Public License as published by
* IBM Corporation; either version 1 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Common Public License for more details.
*
* You should have received a copy of the Common Public License
* along with this program; if not, a copy can be viewed at
* http://www.opensource.org/licenses/cpl1.0.php.
*/
/*
* tpm_specific.c
*
* Feb 10, 2005
*
* Author: Kent Yoder <yoder1@us.ibm.com>
*
* Encryption routines are based on ../soft_stdll/soft_specific.c.
*
*/
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pwd.h>
#include <syslog.h>
#include <openssl/des.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#ifndef NODH
#include <openssl/dh.h>
#endif
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <tss/platform.h>
#include <tss/tcpa_defines.h>
#include <tss/tcpa_typedef.h>
#include <tss/tcpa_struct.h>
#include <tss/tcpa_error.h>
#include <tss/tss_defines.h>
#include <tss/tss_typedef.h>
#include <tss/tss_structs.h>
#include <tss/tss_error.h>
#include <tss/tspi.h>
#include "pkcs11/pkcs11types.h"
#include "pkcs11/stdll.h"
#include "defs.h"
#include "host_defs.h"
#include "args.h"
#include "h_extern.h"
#include "tok_specific.h"
#include "tok_spec_struct.h"
#include "tok_struct.h"
#include "tpm_specific.h"
#include "../api/apiproto.h"
TSS_RESULT util_set_public_modulus(TSS_HKEY, unsigned long, unsigned char *);
CK_CHAR manuf[] = "IBM Corp.";
CK_CHAR model[] = "TPM v1.1 Token";
CK_CHAR descr[] = "Token for the Trusted Platform Module";
CK_CHAR label[] = "IBM PKCS#11 TPM Token";
CK_BYTE master_key_private[MK_SIZE];
/* The context we'll use globally to connect to the TSP */
TSS_HCONTEXT tspContext = NULL_HCONTEXT;
/* TSP key handles */
TSS_HKEY hSRK = NULL_HKEY;
TSS_HKEY hPublicRootKey = NULL_HKEY;
TSS_HKEY hPublicLeafKey = NULL_HKEY;
TSS_HKEY hPrivateRootKey = NULL_HKEY;
TSS_HKEY hPrivateLeafKey = NULL_HKEY;
/* TSP policy handles */
TSS_HPOLICY hDefaultPolicy = NULL_HPOLICY;
/* PKCS#11 key handles */
CK_OBJECT_HANDLE ckPublicRootKey = 0;
CK_OBJECT_HANDLE ckPublicLeafKey = 0;
CK_OBJECT_HANDLE ckPrivateRootKey = 0;
CK_OBJECT_HANDLE ckPrivateLeafKey = 0;
int not_initialized = 0;
CK_BYTE current_user_pin_sha[SHA1_HASH_SIZE];
CK_BYTE current_so_pin_sha[SHA1_HASH_SIZE];
CK_RV
token_specific_session(CK_SLOT_ID slotid)
{
return CKR_OK;
}
CK_RV
token_rng(CK_BYTE *output, CK_ULONG bytes)
{
TSS_RESULT rc;
TSS_HTPM hTPM;
BYTE *random_bytes = NULL;
if ((rc = Tspi_Context_GetTpmObject(tspContext, &hTPM))) {
LogError("Tspi_Context_GetTpmObject: %x", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = Tspi_TPM_GetRandom(hTPM, bytes, &random_bytes))) {
LogError("Tspi_TPM_GetRandom failed. rc=0x%x", rc);
return CKR_FUNCTION_FAILED;
}
memcpy(output, random_bytes, bytes);
Tspi_Context_FreeMemory(tspContext, random_bytes);
return CKR_OK;
}
int
tok_slot2local(CK_SLOT_ID snum)
{
return 1;
}
CK_RV
token_specific_init(char *Correlator, CK_SLOT_ID SlotNumber)
{
TSS_RESULT result;
if ((result = Tspi_Context_Create(&tspContext))) {
LogError("Tspi_Context_Create failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Context_Connect(tspContext, NULL))) {
LogError("Tspi_Context_Connect failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Context_GetDefaultPolicy(tspContext, &hDefaultPolicy))) {
LogError("Tspi_Context_GetDefaultPolicy failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
OpenSSL_add_all_algorithms();
return CKR_OK;
}
CK_RV
token_find_key(int key_type, CK_OBJECT_CLASS class, CK_OBJECT_HANDLE *handle)
{
CK_BYTE *key_id = util_create_id(key_type);
CK_RV rc = CKR_OK;
CK_BBOOL true = TRUE;
CK_ATTRIBUTE tmpl[] = {
{CKA_ID, key_id, strlen((char *)key_id)},
{CKA_CLASS, &class, sizeof(class)},
{CKA_HIDDEN, &true, sizeof(CK_BBOOL)}
};
CK_OBJECT_HANDLE hObj;
CK_ULONG ulObjCount;
SESSION dummy_sess;
/* init the dummy session state to something that will find any object on
* the token */
memset(&dummy_sess, 0, sizeof(SESSION));
dummy_sess.session_info.state = CKS_RO_USER_FUNCTIONS;
if ((rc = object_mgr_find_init(&dummy_sess, tmpl, 3))) {
goto done;
}
/* pulled from SC_FindObjects */
ulObjCount = MIN(1, (dummy_sess.find_count - dummy_sess.find_idx));
memcpy( &hObj, dummy_sess.find_list + dummy_sess.find_idx, ulObjCount * sizeof(CK_OBJECT_HANDLE) );
dummy_sess.find_idx += ulObjCount;
if (ulObjCount > 1) {
LogError1("More than one matching key found in the store!");
rc = CKR_KEY_NOT_FOUND;
goto done;
} else if (ulObjCount < 1) {
LogError("key with ID=\"%s\" not found in the store!", key_id);
rc = CKR_KEY_NOT_FOUND;
goto done;
}
*handle = hObj;
done:
object_mgr_find_final(&dummy_sess);
free(key_id);
return rc;
}
CK_RV
token_get_key_blob(CK_OBJECT_HANDLE ckKey, CK_ULONG *blob_size, CK_BYTE **ret_blob)
{
CK_RV rc = CKR_OK;
CK_BYTE_PTR blob = NULL;
CK_ATTRIBUTE tmpl[] = {
{CKA_IBM_OPAQUE, NULL_PTR, 0}
};
SESSION dummy_sess;
/* set up dummy session */
memset(&dummy_sess, 0, sizeof(SESSION));
dummy_sess.session_info.state = CKS_RO_USER_FUNCTIONS;
/* find object the first time to return the size of the buffer needed */
if ((rc = object_mgr_get_attribute_values(&dummy_sess, ckKey, tmpl, 1))) {
LogError("object_mgr_get_attribute_values failed. rc=0x%lx", rc);
goto done;
}
blob = malloc(tmpl[0].ulValueLen);
if (blob == NULL) {
LogError("malloc of %ld bytes failed.", tmpl[0].ulValueLen);
rc = CKR_HOST_MEMORY;
goto done;
}
tmpl[0].pValue = blob;
/* find object the 2nd time to fill the buffer with data */
if ((rc = object_mgr_get_attribute_values(&dummy_sess, ckKey, tmpl, 1))) {
LogError("object_mgr_get_attribute_values failed. rc=0x%lx", rc);
goto done;
}
*ret_blob = blob;
*blob_size = tmpl[0].ulValueLen;
done:
return rc;
}
CK_RV
token_wrap_sw_key(int size_n, unsigned char *n, int size_p, unsigned char *p,
TSS_HKEY hParentKey, TSS_FLAG initFlags, TSS_HKEY *phKey)
{
TSS_RESULT result;
TSS_HPOLICY hPolicy;
static TSS_BOOL get_srk_pub_key = TRUE;
UINT32 key_size;
key_size = util_get_keysize_flag(size_n * 8);
if (initFlags == 0) {
LogError("Invalid key size.");
return CKR_FUNCTION_FAILED;
}
/* create the TSS key object */
result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_RSAKEY,
TSS_KEY_MIGRATABLE | initFlags | key_size,
phKey);
if (result != TSS_SUCCESS) {
LogError("Tspi_Context_CreateObject failed: rc=0x%x", result);
return result;
}
result = util_set_public_modulus(*phKey, size_n, n);
if (result != TSS_SUCCESS) {
LogError("util_set_public_modulus failed: rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
return result;
}
/* set the private key data in the TSS object */
result = Tspi_SetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB,
TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, size_p, p);
if (result != TSS_SUCCESS) {
LogError("Tspi_SetAttribData failed: rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
return result;
}
/* if the parent wrapping key is the SRK, we need to manually pull
* out the SRK's pub key, which is not stored in persistent storage
* for privacy reasons */
if (hParentKey == hSRK && get_srk_pub_key == TRUE) {
UINT32 pubKeySize;
BYTE *pubKey;
result = Tspi_Key_GetPubKey(hParentKey, &pubKeySize, &pubKey);
if (result != TSS_SUCCESS) {
if (result == TPM_E_INVALID_KEYHANDLE) {
LOG(LOG_WARNING, "Warning: Your TPM is not configured to allow "
"reading the public SRK by anyone but the owner. Use "
"tpm_restrictsrk -a to allow reading the public SRK");
} else {
LogError("Tspi_Key_GetPubKey failed: rc=0x%x", result);
}
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
return result;
}
Tspi_Context_FreeMemory(tspContext, pubKey);
get_srk_pub_key = FALSE;
}
result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_MIGRATION,
&hPolicy);
if (result != TSS_SUCCESS) {
LogError("Tspi_Context_CreateObject: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
return result;
}
result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE, 0, NULL);
if (result != TSS_SUCCESS) {
LogError("Tspi_Policy_SetSecret failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
*phKey = NULL_HKEY;
return result;
}
result = Tspi_Policy_AssignToObject(hPolicy, *phKey);
if (result != TSS_SUCCESS) {
LogError("Tspi_Policy_AssignToObject: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
*phKey = NULL_HKEY;
return result;
}
if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) {
if ((result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
TSS_ES_RSAESPKCSV15))) {
LogError("Tspi_SetAttribUint32 failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
return result;
}
if ((result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
TSS_SS_RSASSAPKCS1V15_DER))) {
LogError("Tspi_SetAttribUint32 failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
return result;
}
}
result = Tspi_Key_WrapKey(*phKey, hParentKey, NULL_HPCRS);
if (result != TSS_SUCCESS) {
LogError("Tspi_Key_WrapKey failed: rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
}
return result;
}
/*
* Create a TPM key blob for an imported key. This function is only called when
* a key is in active use, so any failure should trickle through.
*/
CK_RV
token_wrap_key_object( CK_OBJECT_HANDLE ckObject, TSS_HKEY hParentKey, TSS_HKEY *phKey )
{
CK_RV rc = CKR_OK;
CK_ATTRIBUTE *attr = NULL, *new_attr, *prime_attr;
CK_ULONG class, key_type, pub_exp;
CK_BBOOL found;
OBJECT *obj;
TSS_RESULT result;
TSS_FLAG initFlags = 0;
BYTE *rgbBlob;
UINT32 ulBlobLen;
if ((rc = object_mgr_find_in_map1(ckObject, &obj))) {
LogError("object_mgr_find_in_map1 failed. rc=0x%lx", rc);
return rc;
}
/* if the object isn't a key, fail */
if ((found = template_attribute_find(obj->template, CKA_KEY_TYPE, &attr)) == FALSE) {
LogError1("template_attribute_find(CKA_KEY_TYPE) failed.");
return CKR_FUNCTION_FAILED;
}
key_type = *((CK_ULONG *)attr->pValue);
if (key_type != CKK_RSA) {
LogError("%s: Bad key type!", __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if ((found = template_attribute_find(obj->template, CKA_CLASS, &attr)) == FALSE) {
LogError1("template_attribute_find(CKA_CLASS) failed.");
return CKR_FUNCTION_FAILED;
}
class = *((CK_ULONG *)attr->pValue);
if (class == CKO_PRIVATE_KEY) {
/* In order to create a full TSS key blob using a PKCS#11 private key
* object, we need one of the two primes, the modulus and the private
* exponent and we need the public exponent to be correct */
/* check the least likely attribute to exist first, the primes */
if ((found = template_attribute_find(obj->template, CKA_PRIME_1,
&prime_attr)) == FALSE) {
if ((found = template_attribute_find(obj->template, CKA_PRIME_2,
&prime_attr)) == FALSE) {
LogError1("Couldn't find prime1 or prime2 of key object to wrap");
return CKR_TEMPLATE_INCONSISTENT;
}
}
/* Make sure the public exponent is usable */
if ((util_check_public_exponent(obj->template))) {
LogError("Invalid public exponent");
return CKR_TEMPLATE_INCONSISTENT;
}
/* get the modulus */
if ((found = template_attribute_find(obj->template, CKA_MODULUS,
&attr)) == FALSE) {
LogError1("Couldn't find a required attribute of key object");
return CKR_FUNCTION_FAILED;
}
/* make sure the key size is usable */
initFlags = util_get_keysize_flag(attr->ulValueLen * 8);
if (initFlags == 0) {
LogError("Invalid key size.");
return CKR_TEMPLATE_INCONSISTENT;
}
/* generate the software based key */
if ((rc = token_wrap_sw_key((int)attr->ulValueLen, attr->pValue,
(int)prime_attr->ulValueLen,
prime_attr->pValue,
hParentKey,
TSS_KEY_TYPE_LEGACY | TSS_KEY_NO_AUTHORIZATION,
phKey))) {
LogError("token_wrap_sw_key failed. rc=0x%lu", rc);
return rc;
}
} else if (class == CKO_PUBLIC_KEY) {
/* Make sure the public exponent is usable */
if ((util_check_public_exponent(obj->template))) {
LogError("Invalid public exponent");
return CKR_TEMPLATE_INCONSISTENT;
}
/* grab the modulus to put into the TSS key object */
if ((found = template_attribute_find(obj->template, CKA_MODULUS, &attr))
== FALSE) {
LogError1("Couldn't find a required attribute of key object");
return CKR_TEMPLATE_INCONSISTENT;
}
/* make sure the key size is usable */
initFlags = util_get_keysize_flag(attr->ulValueLen * 8);
if (initFlags == 0) {
LogError("Invalid key size.");
return CKR_TEMPLATE_INCONSISTENT;
}
initFlags |= TSS_KEY_TYPE_LEGACY | TSS_KEY_MIGRATABLE | TSS_KEY_NO_AUTHORIZATION;
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_RSAKEY,
initFlags, phKey))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return result;
}
if ((result = util_set_public_modulus(*phKey, attr->ulValueLen, attr->pValue))) {
LogError("util_set_public_modulus failed: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
return CKR_FUNCTION_FAILED;
}
} else {
LogError("%s: Bad key class!", __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
/* grab the entire key blob to put into the PKCS#11 object */
if ((result = Tspi_GetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB,
TSS_TSPATTRIB_KEYBLOB_BLOB,
&ulBlobLen, &rgbBlob))) {
LogError("Tspi_GetAttribData failed with rc: 0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* insert the key blob into the object */
if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &new_attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
return rc;
}
template_update_attribute( obj->template, new_attr );
Tspi_Context_FreeMemory(tspContext, rgbBlob);
/* if this is a token object, save it with the new attribute so that we
* don't have to go down this path again */
if (!object_is_session_object(obj)) {
rc = save_token_object(obj);
}
return rc;
}
/*
* load a key in the TSS hierarchy from its CK_OBJECT_HANDLE
*/
CK_RV
token_load_key(CK_OBJECT_HANDLE ckKey, TSS_HKEY hParentKey, CK_CHAR_PTR passHash, TSS_HKEY *phKey)
{
TSS_RESULT result;
TSS_HPOLICY hPolicy;
CK_BYTE *blob = NULL;
CK_ULONG ulBlobSize = 0;
CK_RV rc;
if ((rc = token_get_key_blob(ckKey, &ulBlobSize, &blob))) {
if (rc != CKR_ATTRIBUTE_TYPE_INVALID) {
LogError("token_get_key_blob failed. rc=0x%lx", rc);
return rc;
}
/* the key blob wasn't found, so check for a modulus
* to load */
LogError1("key blob not found, checking for modulus");
if ((rc = token_wrap_key_object(ckKey, hParentKey, phKey))) {
LogError("token_wrap_key_object failed. rc=0x%lx", rc);
return rc;
}
}
if (blob != NULL) {
/* load the key inside the TSS */
if ((result = Tspi_Context_LoadKeyByBlob(tspContext, hParentKey, ulBlobSize,
blob, phKey))) {
LogError("Tspi_Context_LoadKeyByBlob: 0x%x", result);
goto done;
}
}
#if 0
if ((result = Tspi_GetPolicyObject(*phKey, TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_GetPolicyObject: 0x%x", result);
goto done;
}
#else
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY,
TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_Context_CreateObject: 0x%x", result);
goto done;
}
#endif
if (passHash == NULL) {
result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE, 0, NULL);
} else {
result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
SHA1_HASH_SIZE, passHash);
}
if (result != TSS_SUCCESS) {
LogError("Tspi_Policy_SetSecret: 0x%x", result);
goto done;
}
if ((result = Tspi_Policy_AssignToObject(hPolicy, *phKey))) {
LogError("Tspi_Policy_AssignToObject: 0x%x", result);
goto done;
}
done:
free(blob);
return result;
}
TSS_RESULT
token_load_srk()
{
TSS_HPOLICY hPolicy;
TSS_RESULT result;
TSS_UUID SRK_UUID = TSS_UUID_SRK;
if (hSRK != NULL_HKEY)
return TSS_SUCCESS;
/* load the SRK */
if ((result = Tspi_Context_LoadKeyByUUID(tspContext, TSS_PS_TYPE_SYSTEM, SRK_UUID,
&hSRK))) {
LogError("Tspi_Context_LoadKeyByUUID failed. rc=0x%x", result);
goto done;
}
#if 0
if ((result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_GetPolicyObject failed. rc=0x%x", result);
goto done;
}
#else
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY,
TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
goto done;
}
if ((result = Tspi_Policy_AssignToObject(hPolicy, hSRK))) {
LogError("Tspi_Policy_AssignToObject failed. rc=0x%x", result);
goto done;
}
#endif
if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_PLAIN, 0, NULL))) {
LogError("Tspi_Policy_SetSecret failed. rc=0x%x", result);
}
done:
return result;
}
TSS_RESULT
token_load_public_root_key()
{
TSS_RESULT result;
BYTE *blob;
CK_ULONG blob_size;
if (hPublicRootKey != NULL_HKEY)
return TSS_SUCCESS;
if ((result = token_load_srk())) {
LogError("token_load_srk failed. rc=0x%x", result);
return result;
}
if ((result = token_find_key(TPMTOK_PUBLIC_ROOT_KEY, CKO_PRIVATE_KEY, &ckPublicRootKey))) {
LogError("token_find_key failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = token_get_key_blob(ckPublicRootKey, &blob_size, &blob))) {
LogError("token_get_key_blob failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* load the Public Root Key */
if ((result = Tspi_Context_LoadKeyByBlob(tspContext, hSRK, blob_size, blob, &hPublicRootKey))) {
LogError("Tspi_Context_LoadKeyByBlob failed. rc=0x%x", result);
free(blob);
return CKR_FUNCTION_FAILED;
}
free(blob);
return result;
}
TSS_RESULT
tss_generate_key(TSS_FLAG initFlags, BYTE *passHash, TSS_HKEY hParentKey, TSS_HKEY *phKey)
{
TSS_RESULT result;
TSS_HPOLICY hPolicy, hMigPolicy;
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_RSAKEY, initFlags,
phKey))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return result;
}
#if 0
if ((result = Tspi_GetPolicyObject(*phKey, TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_GetPolicyObject failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
return result;
}
#else
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY,
TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_Context_CreateObject: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
return result;
}
#endif
if (passHash == NULL) {
result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE, 0, NULL);
} else {
result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, 20, passHash);
}
if (result != TSS_SUCCESS) {
LogError("Tspi_Policy_SetSecret failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
return result;
}
if ((result = Tspi_Policy_AssignToObject(hPolicy, *phKey))) {
LogError("Tspi_Policy_AssignToObject: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
return result;
}
if (TPMTOK_TSS_KEY_MIG_TYPE(initFlags) == TSS_KEY_MIGRATABLE) {
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY,
TSS_POLICY_MIGRATION, &hMigPolicy))) {
LogError("Tspi_Context_CreateObject: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
return result;
}
if (passHash == NULL) {
result = Tspi_Policy_SetSecret(hMigPolicy, TSS_SECRET_MODE_NONE, 0, NULL);
} else {
result = Tspi_Policy_SetSecret(hMigPolicy, TSS_SECRET_MODE_SHA1, 20,
passHash);
}
if (result != TSS_SUCCESS) {
LogError("Tspi_Policy_SetSecret failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
Tspi_Context_CloseObject(tspContext, hMigPolicy);
return result;
}
if ((result = Tspi_Policy_AssignToObject(hMigPolicy, *phKey))) {
LogError("Tspi_Policy_AssignToObject: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
Tspi_Context_CloseObject(tspContext, hMigPolicy);
return result;
}
}
if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) {
if ((result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
TSS_ES_RSAESPKCSV15))) {
LogError("Tspi_SetAttribUint32 failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
Tspi_Context_CloseObject(tspContext, hMigPolicy);
return result;
}
if ((result = Tspi_SetAttribUint32(*phKey, TSS_TSPATTRIB_KEY_INFO,
TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
TSS_SS_RSASSAPKCS1V15_DER))) {
LogError("Tspi_SetAttribUint32 failed. rc=0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
Tspi_Context_CloseObject(tspContext, hMigPolicy);
return result;
}
}
if ((result = Tspi_Key_CreateKey(*phKey, hParentKey, 0))) {
LogError("Tspi_Key_CreateKey failed with rc: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
Tspi_Context_CloseObject(tspContext, hPolicy);
Tspi_Context_CloseObject(tspContext, hMigPolicy);
}
return result;
}
TSS_RESULT
tss_change_auth(TSS_HKEY hObjectToChange, TSS_HKEY hParentObject, CK_CHAR *passHash)
{
TSS_RESULT result;
TSS_HPOLICY hPolicy;
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY,
TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_Context_CreateObject failed: 0x%x", result);
return result;
}
if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1, SHA1_HASH_SIZE, passHash))) {
LogError("Tspi_Policy_SetSecret failed: 0x%x", result);
return result;
}
if ((result = Tspi_ChangeAuth(hObjectToChange, hParentObject, hPolicy))) {
LogError("Tspi_ChangeAuth failed: 0x%x", result);
}
return result;
}
CK_RV
token_store_priv_key(TSS_HKEY hKey, int key_type, CK_OBJECT_HANDLE *ckKey)
{
CK_ATTRIBUTE *new_attr = NULL;
OBJECT *priv_key_obj = NULL;
BYTE *rgbBlob = NULL, *rgbPrivBlob = NULL;
UINT32 ulBlobLen = 0, ulPrivBlobLen = 0;
CK_BBOOL flag;
CK_BYTE *key_id = util_create_id(key_type);
CK_RV rc;
SESSION dummy_sess;
/* set up dummy session */
memset(&dummy_sess, 0, sizeof(SESSION));
dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS;
/* grab the entire key blob to put into the PKCS#11 private key object */
if ((rc = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB,
&ulBlobLen, &rgbBlob))) {
LogError("Tspi_GetAttribData failed with rc: 0x%lx", rc);
free(key_id);
return rc;
}
/* grab the encrypted provate key to put into the object */
if ((rc = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY,
&ulPrivBlobLen, &rgbPrivBlob))) {
LogError("Tspi_GetAttribData failed with rc: 0x%lx", rc);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
free(key_id);
return rc;
}
/* create skeleton for the private key object */
if ((rc = object_create_skel(NULL, 0, MODE_KEYGEN, CKO_PRIVATE_KEY, CKK_RSA, &priv_key_obj))) {
LogError("objectr_create_skel: 0x%lx", rc);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
Tspi_Context_FreeMemory(tspContext, rgbPrivBlob);
free(key_id);
return rc;
}
/* add the ID attribute */
if ((rc = build_attribute(CKA_ID, key_id, strlen((char *)key_id), &new_attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
Tspi_Context_FreeMemory(tspContext, rgbPrivBlob);
free(key_id);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
free(key_id);
/* add the key blob to the PKCS#11 object template */
if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &new_attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
Tspi_Context_FreeMemory(tspContext, rgbPrivBlob);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
Tspi_Context_FreeMemory(tspContext, rgbBlob);
/* add the private key blob to the PKCS#11 object template */
if ((rc = build_attribute(CKA_MODULUS, rgbPrivBlob, ulPrivBlobLen, &new_attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbPrivBlob);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
Tspi_Context_FreeMemory(tspContext, rgbPrivBlob);
/* add the HIDDEN attribute */
flag = TRUE;
if ((rc = build_attribute(CKA_HIDDEN, &flag, sizeof(CK_BBOOL), &new_attr))) {
st_err_log(84, __FILE__, __LINE__);
free(key_id);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
/* set CKA_ALWAYS_SENSITIVE to true */
if ((rc = build_attribute( CKA_ALWAYS_SENSITIVE, &flag, sizeof(CK_BBOOL), &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
/* set CKA_NEVER_EXTRACTABLE to true */
if ((rc = build_attribute( CKA_NEVER_EXTRACTABLE, &flag, sizeof(CK_BBOOL), &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
/* make the object reside on the token, as if that were possible */
if ((rc = build_attribute( CKA_TOKEN, &flag, sizeof(CK_BBOOL), &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
flag = FALSE;
if ((rc = build_attribute( CKA_PRIVATE, &flag, sizeof(CK_BBOOL), &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( priv_key_obj->template, new_attr );
if ((rc = object_mgr_create_final(&dummy_sess, priv_key_obj, ckKey))) {
st_err_log(90, __FILE__, __LINE__);
}
return rc;
}
CK_RV
token_store_pub_key(TSS_HKEY hKey, int key_type, CK_OBJECT_HANDLE *ckKey)
{
CK_RV rc;
TSS_RESULT result;
CK_ATTRIBUTE *new_attr = NULL;
OBJECT *pub_key_obj;
CK_BBOOL flag = TRUE;
CK_OBJECT_CLASS pub_class = CKO_PUBLIC_KEY;
CK_KEY_TYPE type = CKK_RSA;
CK_BYTE *key_id = util_create_id(key_type);
CK_BYTE pub_exp[] = { 0x1, 0x0, 0x1 }; // 65537
CK_ATTRIBUTE pub_tmpl[] = {
{CKA_CLASS, &pub_class, sizeof(pub_class)},
{CKA_KEY_TYPE, &type, sizeof(type)},
{CKA_ID, key_id, strlen((char *)key_id)},
{CKA_PUBLIC_EXPONENT, pub_exp, sizeof(pub_exp)},
{CKA_MODULUS, NULL_PTR, 0}
};
BYTE *rgbPubBlob = NULL;
UINT32 ulBlobLen = 0;
SESSION dummy_sess;
/* set up dummy session */
memset(&dummy_sess, 0, sizeof(SESSION));
dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS;
/* grab the public key to put into the PKCS#11 public key object */
if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
TSS_TSPATTRIB_KEYINFO_RSA_MODULUS,
&ulBlobLen, &rgbPubBlob))) {
LogError("Tspi_GetAttribData failed with rc: 0x%x", result);
Tspi_Context_CloseObject(tspContext, hKey);
free(key_id);
return result;
}
pub_tmpl[4].pValue = rgbPubBlob;
pub_tmpl[4].ulValueLen = ulBlobLen;
/* create skeleton for the private key object */
if ((rc = object_create_skel(pub_tmpl, 5, MODE_CREATE, CKO_PUBLIC_KEY, CKK_RSA, &pub_key_obj))) {
LogError("object_create_skel: 0x%lx", rc);
Tspi_Context_CloseObject(tspContext, hKey);
free(key_id);
return rc;
}
Tspi_Context_FreeMemory(tspContext, rgbPubBlob);
/* make the object reside on the token, as if that were possible */
if ((rc = build_attribute( CKA_TOKEN, &flag, sizeof(CK_BBOOL), &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
goto done;
}
template_update_attribute( pub_key_obj->template, new_attr );
/* set the object to be hidden */
if ((rc = build_attribute( CKA_HIDDEN, &flag, sizeof(CK_BBOOL), &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
goto done;
}
template_update_attribute( pub_key_obj->template, new_attr );
if ((rc = object_mgr_create_final(&dummy_sess, pub_key_obj, ckKey))) {
st_err_log(90, __FILE__, __LINE__);
goto done;
}
done:
return rc;
}
CK_RV
token_update_private_key(TSS_HKEY hKey, int key_type)
{
CK_OBJECT_HANDLE ckHandle;
CK_RV rc;
SESSION dummy_sess;
/* set up dummy session */
memset(&dummy_sess, 0, sizeof(SESSION));
dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS;
/* find the private key portion of the key */
if ((rc = token_find_key(key_type, CKO_PRIVATE_KEY, &ckHandle))) {
LogError("token_find_key failed: 0x%lx", rc);
return rc;
}
/* destroy the private key and create a new one */
if ((rc = object_mgr_destroy_object(&dummy_sess, ckHandle))) {
LogError("object_mgr_destroy_object failed: 0x%lx", rc);
return rc;
}
if ((rc = token_store_priv_key(hKey, key_type, &ckHandle))) {
LogError("token_store_priv_key failed: 0x%lx", rc);
}
return rc;
}
CK_RV
token_store_tss_key(TSS_HKEY hKey, int key_type, CK_OBJECT_HANDLE *ckKey)
{
CK_RV rc;
/* create a PKCS#11 pub key object for the key */
if ((rc = token_store_pub_key(hKey, key_type, ckKey))) {
LogError("token_store_pub_key failed. rc=0x%lx", rc);
return rc;
}
/* create a PKCS#11 private key object for the key */
if ((rc = token_store_priv_key(hKey, key_type, ckKey))) {
LogError("token_store_priv_key failed. rc=0x%lx", rc);
}
return rc;
}
CK_RV
token_generate_leaf_key(int key_type, CK_CHAR_PTR passHash, TSS_HKEY *phKey)
{
CK_RV rc = CKR_FUNCTION_FAILED;
TSS_RESULT result;
TSS_HKEY hParentKey;
CK_OBJECT_HANDLE *ckKey;
TSS_FLAG initFlags = TSS_KEY_MIGRATABLE | TSS_KEY_TYPE_BIND |
TSS_KEY_SIZE_2048 | TSS_KEY_AUTHORIZATION;
switch (key_type) {
case TPMTOK_PUBLIC_LEAF_KEY:
hParentKey = hPublicRootKey;
ckKey = &ckPublicRootKey;
break;
case TPMTOK_PRIVATE_LEAF_KEY:
hParentKey = hPrivateRootKey;
ckKey = &ckPrivateRootKey;
break;
default:
LogError1("Oh NO");
goto done;
break;
}
if ((result = tss_generate_key(initFlags, passHash, hParentKey, phKey))) {
LogError("tss_generate_key returned 0x%x", result);
return result;
}
if ((rc = token_store_tss_key(*phKey, key_type, ckKey))) {
LogError("token_store_tss_key failed. rc=0x%x", result);
}
done:
return rc;
}
CK_RV
token_verify_pin(TSS_HKEY hKey)
{
TSS_HENCDATA hEncData;
UINT32 ulUnboundDataLen;
BYTE *rgbUnboundData;
char *rgbData = "CRAPPENFEST";
TSS_RESULT result;
CK_RV rc = CKR_FUNCTION_FAILED;
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
goto done;
}
if ((result = Tspi_Data_Bind(hEncData, hKey, strlen(rgbData), (BYTE *)rgbData))) {
LogError("%s: Bind returned 0x%x", __FUNCTION__, result);
goto done;
}
/* unbind the junk data to test the key's auth data */
result = Tspi_Data_Unbind(hEncData, hKey, &ulUnboundDataLen, &rgbUnboundData);
if (result == TCPA_E_AUTHFAIL) {
rc = CKR_PIN_INCORRECT;
LogError("%s: Unbind returned TCPA_AUTHFAIL", __FUNCTION__);
goto done;
} else if (result != TSS_SUCCESS) {
LogError("%s: Unbind returned 0x%x", __FUNCTION__, result);
goto done;
}
rc = memcmp(rgbUnboundData, rgbData, ulUnboundDataLen);
Tspi_Context_FreeMemory(tspContext, rgbUnboundData);
done:
Tspi_Context_CloseObject(tspContext, hEncData);
return rc;
}
CK_RV
token_create_private_tree(CK_BYTE *pinHash, CK_BYTE *pPin)
{
CK_RV rc;
TSS_RESULT result;
RSA *rsa;
unsigned int size_n, size_p;
unsigned char n[256], p[256];
/* all sw generated keys are 2048 bits */
if ((rsa = openssl_gen_key()) == NULL)
return CKR_HOST_MEMORY;
if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) {
LogError1("openssl_get_modulus_and_prime failed");
return CKR_FUNCTION_FAILED;
}
/* generate the software based user base key */
if ((rc = token_wrap_sw_key(size_n, n, size_p, p, hSRK,
TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE,
&hPrivateRootKey))) {
LogError("token_wrap_sw_key failed. rc=0x%lu", rc);
return rc;
}
if (openssl_write_key(rsa, TPMTOK_PRIV_ROOT_KEY_FILE, pPin)) {
LogError1("openssl_write_key");
RSA_free(rsa);
return CKR_FUNCTION_FAILED;
}
RSA_free(rsa);
/* store the user base key in a PKCS#11 object internally */
if ((rc = token_store_tss_key(hPrivateRootKey, TPMTOK_PRIVATE_ROOT_KEY, &ckPrivateRootKey))) {
LogError("token_store_tss_key failed. rc=0x%lx", rc);
return rc;
}
if ((result = Tspi_Key_LoadKey(hPrivateRootKey, hSRK))) {
LogError("Tspi_Key_LoadKey: 0x%x", result);
Tspi_Context_CloseObject(tspContext, hPrivateRootKey);
hPrivateRootKey = NULL_HKEY;
return CKR_FUNCTION_FAILED;
}
/* generate the private leaf key */
if ((rc = token_generate_leaf_key(TPMTOK_PRIVATE_LEAF_KEY, pinHash, &hPrivateLeafKey))) {
LogError("token_generate_leaf_key failed. rc=0x%lx", rc);
return rc;
}
if ((result = Tspi_Key_LoadKey(hPrivateLeafKey, hPrivateRootKey))) {
LogError("Tspi_Key_LoadKey: 0x%x", result);
Tspi_Context_CloseObject(tspContext, hPrivateRootKey);
hPrivateRootKey = NULL_HKEY;
Tspi_Context_CloseObject(tspContext, hPrivateLeafKey);
hPrivateRootKey = NULL_HKEY;
return CKR_FUNCTION_FAILED;
}
return rc;
}
CK_RV
token_create_public_tree(CK_BYTE *pinHash, CK_BYTE *pPin)
{
CK_RV rc;
TSS_RESULT result;
RSA *rsa;
unsigned int size_n, size_p;
unsigned char n[256], p[256];
/* all sw generated keys are 2048 bits */
if ((rsa = openssl_gen_key()) == NULL)
return CKR_HOST_MEMORY;
if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) {
LogError1("openssl_get_modulus_and_prime failed");
return CKR_FUNCTION_FAILED;
}
/* create the public root key */
if ((rc = token_wrap_sw_key(size_n, n, size_p, p, hSRK,
TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE,
&hPublicRootKey))) {
LogError("token_wrap_sw_key failed. rc=0x%lx", rc);
return rc;
}
if (openssl_write_key(rsa, TPMTOK_PUB_ROOT_KEY_FILE, pPin)) {
LogError1("openssl_write_key");
RSA_free(rsa);
return CKR_FUNCTION_FAILED;
}
RSA_free(rsa);
if ((result = Tspi_Key_LoadKey(hPublicRootKey, hSRK))) {
LogError("Tspi_Key_LoadKey: 0x%x", result);
Tspi_Context_CloseObject(tspContext, hPublicRootKey);
hPublicRootKey = NULL_HKEY;
return CKR_FUNCTION_FAILED;
}
if ((rc = token_store_tss_key(hPublicRootKey, TPMTOK_PUBLIC_ROOT_KEY, &ckPublicRootKey))) {
LogError("token_store_tss_key failed. rc=0x%lx", rc);
return rc;
}
/* create the SO's leaf key */
if ((rc = token_generate_leaf_key(TPMTOK_PUBLIC_LEAF_KEY, pinHash, &hPublicLeafKey))) {
LogError("token_generate_leaf_key failed. rc=0x%lx", rc);
return rc;
}
if ((result = Tspi_Key_LoadKey(hPublicLeafKey, hPublicRootKey))) {
LogError("Tspi_Key_LoadKey: 0x%x", result);
Tspi_Context_CloseObject(tspContext, hPublicRootKey);
hPublicRootKey = NULL_HKEY;
Tspi_Context_CloseObject(tspContext, hPublicLeafKey);
hPublicLeafKey = NULL_HKEY;
return CKR_FUNCTION_FAILED;
}
return rc;
}
CK_RV
token_migrate(int key_type, CK_BYTE *pin)
{
RSA *rsa;
char *backup_loc;
unsigned int size_n, size_p;
unsigned char n[256], p[256];
TSS_RESULT result;
TSS_HKEY *phKey;
CK_RV rc;
CK_OBJECT_HANDLE *ckHandle;
SESSION dummy_sess;
/* set up dummy session */
memset(&dummy_sess, 0, sizeof(SESSION));
dummy_sess.session_info.state = CKS_RW_USER_FUNCTIONS;
if (key_type == TPMTOK_PUBLIC_ROOT_KEY) {
backup_loc = TPMTOK_PUB_ROOT_KEY_FILE;
phKey = &hPublicRootKey;
ckHandle = &ckPublicRootKey;
} else if (key_type == TPMTOK_PRIVATE_ROOT_KEY) {
backup_loc = TPMTOK_PRIV_ROOT_KEY_FILE;
phKey = &hPrivateRootKey;
ckHandle = &ckPrivateRootKey;
} else {
LogError1("Invalid key type.");
return CKR_FUNCTION_FAILED;
}
/* read the backup key with the old pin */
if ((rc = openssl_read_key(backup_loc, pin, &rsa))) {
LogError1("openssl_read_key failed");
return rc;
}
/* So, reading the backup openssl key off disk succeeded with the SOs PIN.
* We will now try to re-wrap that key with the current SRK
*/
if (openssl_get_modulus_and_prime(rsa, &size_n, n, &size_p, p) != 0) {
LogError1("openssl_get_modulus_and_prime failed");
return CKR_FUNCTION_FAILED;
}
if ((rc = token_wrap_sw_key(size_n, n, size_p, p, hSRK,
TSS_KEY_TYPE_STORAGE | TSS_KEY_NO_AUTHORIZATION,
phKey))) {
LogError("token_wrap_sw_key failed. rc=0x%lx", rc);
RSA_free(rsa);
return rc;
}
RSA_free(rsa);
if ((result = Tspi_Key_LoadKey(*phKey, hSRK))) {
LogError("Tspi_Key_LoadKey: 0x%x", result);
Tspi_Context_CloseObject(tspContext, *phKey);
*phKey = NULL_HKEY;
return CKR_FUNCTION_FAILED;
}
/* Loading succeeded, so we need to get rid of the old PKCS#11 objects
* and store them anew.
*/
if ((rc = token_find_key(key_type, CKO_PUBLIC_KEY, ckHandle))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = object_mgr_destroy_object(&dummy_sess, *ckHandle))) {
LogError("object_mgr_destroy_object failed: 0x%lx", rc);
return rc;
}
if ((rc = token_find_key(key_type, CKO_PRIVATE_KEY, ckHandle))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = object_mgr_destroy_object(&dummy_sess, *ckHandle))) {
LogError("object_mgr_destroy_object failed: 0x%lx", rc);
return rc;
}
if ((rc = token_store_tss_key(*phKey, key_type, ckHandle))) {
LogError("token_store_tss_key failed: 0x%lx", rc);
return rc;
}
return CKR_OK;
}
CK_RV
save_masterkey_private()
{
char fname[PATH_MAX];
struct stat file_stat;
int err;
FILE *fp = NULL;
struct passwd *pw = NULL;
TSS_RESULT result;
TSS_HENCDATA hEncData;
BYTE *encrypted_masterkey;
UINT32 encrypted_masterkey_size;
if ((pw = getpwuid(getuid())) == NULL) {
LogError("getpwuid failed: %s", strerror(errno));
return CKR_FUNCTION_FAILED;
}
//fp = fopen("/etc/pkcs11/tpm/MK_PRIVATE", "r");
sprintf((char *)fname,"%s/%s/%s", pk_dir, pw->pw_name, TPMTOK_MASTERKEY_PRIVATE);
/* if file exists, assume its been written correctly before */
if ((err = stat(fname, &file_stat)) == 0) {
return CKR_OK;
} else if (errno != ENOENT) {
/* some error other than file doesn't exist */
return CKR_FUNCTION_FAILED;
}
/* encrypt the private masterkey using the private leaf key */
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Data_Bind(hEncData, hPrivateLeafKey, MK_SIZE, master_key_private))) {
LogError("Tspi_Data_Bind failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
TSS_TSPATTRIB_ENCDATABLOB_BLOB, &encrypted_masterkey_size,
&encrypted_masterkey))) {
LogError("Tspi_GetAttribData failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if (encrypted_masterkey_size > 256) {
Tspi_Context_FreeMemory(tspContext, encrypted_masterkey);
return CKR_DATA_LEN_RANGE;
}
/* write the encrypted key to disk */
if ((fp = fopen((char *)fname, "w")) == NULL) {
LogError("Error opening %s for write: %s", fname, strerror(errno));
Tspi_Context_FreeMemory(tspContext, encrypted_masterkey);
return CKR_FUNCTION_FAILED;
}
if ((err = fwrite(encrypted_masterkey, encrypted_masterkey_size, 1, fp)) == 0) {
LogError("Error writing %s: %s", fname, strerror(errno));
Tspi_Context_FreeMemory(tspContext, encrypted_masterkey);
fclose(fp);
return CKR_FUNCTION_FAILED;
}
Tspi_Context_FreeMemory(tspContext, encrypted_masterkey);
fclose(fp);
return CKR_OK;
}
CK_RV
load_masterkey_private()
{
FILE *fp = NULL;
int err;
struct stat file_stat;
CK_BYTE encrypted_masterkey[256];
char fname[PATH_MAX];
CK_RV rc;
struct passwd *pw = NULL;
TSS_RESULT result;
TSS_HENCDATA hEncData;
BYTE *masterkey;
UINT32 masterkey_size, encrypted_masterkey_size = 256;
if ((pw = getpwuid(getuid())) == NULL) {
LogError("getpwuid failed: %s", strerror(errno));
return CKR_FUNCTION_FAILED;
}
sprintf((char *)fname,"%s/%s/%s", pk_dir, pw->pw_name, TPMTOK_MASTERKEY_PRIVATE);
/* if file exists, check its size */
if ((err = stat(fname, &file_stat)) == 0) {
if (file_stat.st_size != 256) {
LogError1("Private master key has been corrupted");
return CKR_FUNCTION_FAILED;
}
} else if (errno == ENOENT) {
LogError1("Private master key doesn't exist, creating it...");
/* create the private master key, then save */
if ((rc = token_rng(master_key_private, MK_SIZE))) {
LogError("token_rng failed. rc=0x%lx", rc);
return rc;
}
return save_masterkey_private();
} else {
/* some error other than file doesn't exist */
LogError("stat of private masterkey failed: %s", strerror(errno));
return CKR_FUNCTION_FAILED;
}
//fp = fopen("/etc/pkcs11/tpm/MK_PUBLIC", "r");
if ((fp = fopen((char *)fname, "r")) == NULL) {
LogError("Error opening %s: %s", fname, strerror(errno));
return CKR_FUNCTION_FAILED;
}
if (fread(encrypted_masterkey, encrypted_masterkey_size, 1, fp) == 0) {
LogError("Error reading %s: %s", fname, strerror(errno));
fclose(fp);
return CKR_FUNCTION_FAILED;
}
fclose(fp);
/* decrypt the private masterkey using the private leaf key */
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
TSS_TSPATTRIB_ENCDATABLOB_BLOB, encrypted_masterkey_size,
encrypted_masterkey))) {
LogError("Tspi_SetAttribData failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Data_Unbind(hEncData, hPrivateLeafKey, &masterkey_size, &masterkey))) {
LogError("Tspi_Data_Unbind failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if (masterkey_size != MK_SIZE) {
LogError("decrypted private master key size is %u, should be %u",
masterkey_size, MK_SIZE);
Tspi_Context_FreeMemory(tspContext, masterkey);
return CKR_FUNCTION_FAILED;
}
memcpy(master_key_private, masterkey, MK_SIZE);
Tspi_Context_FreeMemory(tspContext, masterkey);
return CKR_OK;
}
CK_RV
token_specific_login(CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
{
CK_RV rc;
CK_BYTE hash_sha[SHA1_HASH_SIZE];
TSS_RESULT result;
if ((result = token_load_srk())) {
LogError("token_load_srk failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((rc = compute_sha(pPin, ulPinLen, hash_sha))) {
LogError("compute_sha failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if (userType == CKU_USER) {
/* If the public root key doesn't exist yet, the SO hasn't init'd the token */
if ((result = token_load_public_root_key())) {
LogError("token_load_public_root_key failed. rc=0x%x", result);
return CKR_USER_PIN_NOT_INITIALIZED;
}
/* find, load the private root key */
if ((rc = token_find_key(TPMTOK_PRIVATE_ROOT_KEY, CKO_PRIVATE_KEY, &ckPrivateRootKey))) {
/* user's key chain not found, this must be the initial login */
if (memcmp(hash_sha, default_user_pin_sha, SHA1_HASH_SIZE)) {
LogError("token_find_key failed and PIN != default");
return CKR_PIN_INCORRECT;
}
not_initialized = 1;
return CKR_OK;
}
if ((rc = token_load_key(ckPrivateRootKey, hSRK, NULL, &hPrivateRootKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
/* Here, we've found the private root key, but its load failed.
* This should only happen in a migration path, where we have
* the PKCS#11 key store available, but the SRK is now
* different. So, we will try to decrypt the PEM backup file
* for the private root key using the given password. If that
* succeeds, we will assume that we're in a migration path and
* re-wrap the private root key to the new SRK.
*/
if ((token_migrate(TPMTOK_PRIVATE_ROOT_KEY, pPin))) {
LogError("token_migrate. rc=0x%lx", rc);
return rc;
}
/* At this point, the public root key has been successfully read
* from backup, re-wrapped to the new SRK, loaded and the PKCS#11
* objects have been updated. Proceed with login as normal.
*/
}
/* find, load the user leaf key */
if ((rc = token_find_key(TPMTOK_PRIVATE_LEAF_KEY, CKO_PRIVATE_KEY, &ckPrivateLeafKey))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_load_key(ckPrivateLeafKey, hPrivateRootKey, hash_sha, &hPrivateLeafKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_verify_pin(hPrivateLeafKey))) {
LogError("token_verify_pin failed. failed. rc=0x%lx", rc);
return rc;
}
memcpy(current_user_pin_sha, hash_sha, SHA1_HASH_SIZE);
/* load private data encryption key here */
if ((rc = load_masterkey_private())) {
LogError("load_masterkey_private failed. rc=0x%lx", rc);
Tspi_Key_UnloadKey(hPrivateLeafKey);
hPrivateLeafKey = NULL_HKEY;
return rc;
}
rc = load_private_token_objects();
XProcLock( xproclock );
global_shm->priv_loaded = TRUE;
XProcUnLock( xproclock );
} else {
/* SO path --
*/
/* find, load the root key */
if ((rc = token_find_key(TPMTOK_PUBLIC_ROOT_KEY, CKO_PRIVATE_KEY, &ckPublicRootKey))) {
/* The SO hasn't set her PIN yet, compare the login pin with
* the hard-coded value */
if (memcmp(default_so_pin_sha, hash_sha, SHA1_HASH_SIZE)) {
LogError("token_find_key failed and PIN != default");
return CKR_PIN_INCORRECT;
}
not_initialized = 1;
return CKR_OK;
}
/* The SO's key hierarchy has previously been created, so load the key
* hierarchy and verify the pin using the TPM. */
if ((rc = token_load_key(ckPublicRootKey, hSRK, NULL, &hPublicRootKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
/* Here, we've found the public root key, but its load failed.
* This should only happen in a migration path, where we have
* the PKCS#11 key store available, but the SRK is now
* different. So, we will try to decrypt the PEM backup file
* for the public root key using the given password. If that
* succeeds, we will assume that we're in a migration path and
* re-wrap the public root key to the new SRK.
*/
if ((token_migrate(TPMTOK_PUBLIC_ROOT_KEY, pPin))) {
LogError("token_migrate. rc=0x%lx", rc);
return rc;
}
/* At this point, the public root key has been successfully read
* from backup, re-wrapped to the new SRK, loaded and the PKCS#11
* objects have been updated. Proceed with login as normal.
*/
}
/* find, load the public leaf key */
if ((rc = token_find_key(TPMTOK_PUBLIC_LEAF_KEY, CKO_PRIVATE_KEY, &ckPublicLeafKey))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_load_key(ckPublicLeafKey, hPublicRootKey, hash_sha, &hPublicLeafKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_verify_pin(hPublicLeafKey))) {
LogError("token_verify_pin failed. rc=0x%lx", rc);
return rc;
}
memcpy(current_so_pin_sha, hash_sha, SHA1_HASH_SIZE);
}
return rc;
}
CK_RV
token_specific_logout()
{
if (hPrivateLeafKey != NULL_HKEY) {
Tspi_Key_UnloadKey(hPrivateLeafKey);
hPrivateLeafKey = NULL_HKEY;
} else if (hPublicLeafKey != NULL_HKEY) {
Tspi_Key_UnloadKey(hPublicLeafKey);
hPublicLeafKey = NULL_HKEY;
}
memset(master_key_private, 0, MK_SIZE);
memset(current_so_pin_sha, 0, SHA1_HASH_SIZE);
memset(current_user_pin_sha, 0, SHA1_HASH_SIZE);
/* pulled from new_host.c */
object_mgr_purge_private_token_objects();
return CKR_OK;
}
CK_RV
token_specific_init_pin(CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
{
/* Since the SO must log in before calling C_InitPIN, we will
* be able to return CKR_OK automatically here.
* This is because the USER key structure is created at the
* time of her first login, not at C_InitPIN time.
*/
return CKR_OK;
}
CK_RV
check_pin_properties(CK_USER_TYPE userType, CK_BYTE *pinHash, CK_ULONG ulPinLen)
{
/* make sure the new PIN is different */
if (userType == CKU_USER) {
if (!memcmp(pinHash, default_user_pin_sha, SHA1_HASH_SIZE)) {
LogError("new PIN must not be the default");
return CKR_PIN_INVALID;
}
} else {
if (!memcmp(pinHash, default_so_pin_sha, SHA1_HASH_SIZE)) {
LogError("new PIN must not be the default");
return CKR_PIN_INVALID;
}
}
if (ulPinLen > MAX_PIN_LEN || ulPinLen < MIN_PIN_LEN) {
LogError("New PIN is out of size range");
return CKR_PIN_LEN_RANGE;
}
return CKR_OK;
}
/* use this function call from set_pin only, where a not logged in public
* session can provide the user pin which must be verified. This function
* assumes that the pin has already been set once, so there's no migration
* path option or checking of the default user pin.
*/
CK_RV
verify_user_pin(CK_BYTE *hash_sha)
{
CK_RV rc;
/* find, load the private root key */
if ((rc = token_find_key(TPMTOK_PRIVATE_ROOT_KEY, CKO_PRIVATE_KEY,
&ckPrivateRootKey))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_load_key(ckPrivateRootKey, hSRK, NULL,
&hPrivateRootKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
/* find, load the user leaf key */
if ((rc = token_find_key(TPMTOK_PRIVATE_LEAF_KEY, CKO_PRIVATE_KEY,
&ckPrivateLeafKey))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_load_key(ckPrivateLeafKey, hPrivateRootKey, hash_sha,
&hPrivateLeafKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_verify_pin(hPrivateLeafKey))) {
LogError("token_verify_pin failed. failed. rc=0x%lx", rc);
return rc;
}
return CKR_OK;
}
CK_RV
token_specific_set_pin(ST_SESSION_HANDLE session,
CK_CHAR_PTR pOldPin, CK_ULONG ulOldPinLen,
CK_CHAR_PTR pNewPin, CK_ULONG ulNewPinLen)
{
SESSION *sess = session_mgr_find( session.sessionh );
CK_BYTE oldpin_hash[SHA1_HASH_SIZE], newpin_hash[SHA1_HASH_SIZE];
CK_RV rc;
RSA *rsa_root;
TSS_RESULT result;
if (!sess) {
st_err_log(40, __FILE__, __LINE__);
return CKR_SESSION_HANDLE_INVALID;
}
if ((rc = compute_sha(pOldPin, ulOldPinLen, oldpin_hash))) {
LogError("compute_sha failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = compute_sha(pNewPin, ulNewPinLen, newpin_hash))) {
LogError("compute_sha failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((result = token_load_srk())) {
LogError("token_load_srk failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* From the PKCS#11 2.20 spec: "C_SetPIN modifies the PIN of the user that is
* currently logged in, or the CKU_USER PIN if the session is not logged in."
* A non R/W session fails with CKR_SESSION_READ_ONLY.
*/
if (sess->session_info.state == CKS_RW_USER_FUNCTIONS ||
sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
if (not_initialized) {
if (memcmp(oldpin_hash, default_user_pin_sha,
SHA1_HASH_SIZE)) {
LogError("old PIN != default for an uninitialized user");
return CKR_PIN_INCORRECT;
}
if ((rc = check_pin_properties(CKU_USER, newpin_hash,
ulNewPinLen))) {
return rc;
}
if ((rc = token_create_private_tree(newpin_hash,
pNewPin))) {
LogError1("FAILED creating USER tree.");
return CKR_FUNCTION_FAILED;
}
nv_token_data->token_info.flags &= ~(CKF_USER_PIN_TO_BE_CHANGED);
nv_token_data->token_info.flags |= CKF_USER_PIN_INITIALIZED;
return save_token_data();
}
if (sess->session_info.state == CKS_RW_USER_FUNCTIONS) {
/* if we're already logged in, just verify the hash */
if (memcmp(current_user_pin_sha, oldpin_hash,
SHA1_HASH_SIZE)) {
LogError("USER pin incorrect");
return CKR_PIN_INCORRECT;
}
} else {
if ((rc = verify_user_pin(oldpin_hash))) {
return rc;
}
}
if ((rc = check_pin_properties(CKU_USER, newpin_hash,
ulNewPinLen))) {
return rc;
}
/* change the auth on the TSS object */
if ((result = tss_change_auth(hPrivateLeafKey, hPrivateRootKey, newpin_hash))) {
LogError1("tss_change_auth failed");
return CKR_FUNCTION_FAILED;
}
/* destroy the old PKCS#11 priv key object and create a new one */
if ((rc = token_update_private_key(hPrivateLeafKey, TPMTOK_PRIVATE_LEAF_KEY))) {
LogError1("token_update_private_key failed.");
return rc;
}
/* read the backup key with the old pin */
if ((rc = openssl_read_key(TPMTOK_PRIV_ROOT_KEY_FILE, pOldPin, &rsa_root))) {
if (rc == CKR_FILE_NOT_FOUND) {
/* If the user has moved his backup PEM file off site, allow a
* change auth to succeed without updating it. */
return CKR_OK;
}
LogError1("openssl_read_key failed");
return rc;
}
/* write it out using the new pin */
if ((rc = openssl_write_key(rsa_root, TPMTOK_PRIV_ROOT_KEY_FILE, pNewPin))) {
RSA_free(rsa_root);
LogError1("openssl_write_key failed");
return CKR_FUNCTION_FAILED;
}
RSA_free(rsa_root);
} else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
if (not_initialized) {
if (memcmp(default_so_pin_sha, oldpin_hash, SHA1_HASH_SIZE)) {
LogError("old PIN != default for an uninitialized SO");
return CKR_PIN_INCORRECT;
}
if ((rc = check_pin_properties(CKU_SO, newpin_hash, ulNewPinLen))) {
return rc;
}
if ((rc = token_create_public_tree(newpin_hash, pNewPin))) {
LogError1("FAILED creating SO tree.");
return CKR_FUNCTION_FAILED;
}
nv_token_data->token_info.flags &= ~(CKF_SO_PIN_TO_BE_CHANGED);
return save_token_data();
}
if (memcmp(current_so_pin_sha, oldpin_hash, SHA1_HASH_SIZE)) {
LogError("SO PIN incorrect");
return CKR_PIN_INCORRECT;
}
if ((rc = check_pin_properties(CKU_SO, newpin_hash, ulNewPinLen))) {
return rc;
}
/* change auth on the SO's leaf key */
if ((result = tss_change_auth(hPublicLeafKey, hPublicRootKey, newpin_hash))) {
LogError1("tss_change_auth failed");
return CKR_FUNCTION_FAILED;
}
if ((rc = token_update_private_key(hPublicLeafKey, TPMTOK_PUBLIC_LEAF_KEY))) {
LogError1("token_update_private_key failed.");
return rc;
}
/* change auth on the public root key's openssl backup */
if ((rc = openssl_read_key(TPMTOK_PUB_ROOT_KEY_FILE, pOldPin, &rsa_root))) {
if (rc == CKR_FILE_NOT_FOUND) {
/* If the user has moved his backup PEM file off site, allow a
* change auth to succeed without updating it. */
return CKR_OK;
}
LogError1("openssl_read_key failed");
return rc;
}
/* write it out using the new pin */
if ((rc = openssl_write_key(rsa_root, TPMTOK_PUB_ROOT_KEY_FILE, pNewPin))) {
RSA_free(rsa_root);
LogError1("openssl_write_key failed");
return CKR_FUNCTION_FAILED;
}
RSA_free(rsa_root);
} else {
st_err_log(142, __FILE__, __LINE__);
rc = CKR_SESSION_READ_ONLY;
}
return rc;
}
/* only called at token init time */
CK_RV
token_specific_verify_so_pin(CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
{
CK_BYTE hash_sha[SHA1_HASH_SIZE];
CK_RV rc;
if ((rc = compute_sha(pPin, ulPinLen, hash_sha))) {
LogError("compute_sha failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
/* find, load the migratable root key */
if ((rc = token_find_key(TPMTOK_PUBLIC_ROOT_KEY, CKO_PRIVATE_KEY, &ckPublicRootKey))) {
/* The SO hasn't set her PIN yet, compare the login pin with
* the hard-coded value */
if (memcmp(default_so_pin_sha, hash_sha, SHA1_HASH_SIZE)) {
LogError("token_find_key failed and PIN != default");
return CKR_PIN_INCORRECT;
}
return CKR_OK;
}
if ((rc = token_load_srk())) {
LogError("token_load_srk failed. rc = 0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
/* we found the root key, so check by loading the chain */
if ((rc = token_load_key(ckPublicRootKey, hSRK, NULL, &hPublicRootKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
/* find, load the public leaf key */
if ((rc = token_find_key(TPMTOK_PUBLIC_LEAF_KEY, CKO_PRIVATE_KEY, &ckPublicLeafKey))) {
LogError("token_find_key failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
if ((rc = token_load_key(ckPublicLeafKey, hPublicRootKey, hash_sha, &hPublicLeafKey))) {
LogError1("token_load_key(MigLeafKey) Failed.");
return CKR_FUNCTION_FAILED;
}
if ((rc = token_verify_pin(hPublicLeafKey))) {
LogError("token_verify_pin failed. rc=0x%lx", rc);
return rc;
}
return CKR_OK;
}
CK_RV
token_specific_final()
{
TSS_RESULT result;
if ((result = Tspi_Context_Close(tspContext))) {
LogError("Tspi_Context_Close failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
CK_RV
token_specific_des_key_gen(CK_BYTE *des_key, CK_ULONG len)
{
// Nothing different to do for DES or TDES here as this is just
// random data... Validation handles the rest
rng_generate(des_key,len);
// we really need to validate the key for parity etc...
// we should do that here... The caller validates the single des keys
// against the known and suspected poor keys..
return CKR_OK;
}
CK_RV
token_specific_des_ecb(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len,
CK_BYTE *key_value,
CK_BYTE encrypt)
{
CK_ULONG rc;
des_key_schedule des_key2;
const_des_cblock key_val_SSL, in_key_data;
des_cblock out_key_data;
unsigned int i,j;
// Create the key schedule
memcpy(&key_val_SSL, key_value, 8);
des_set_key_unchecked(&key_val_SSL, des_key2);
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % 8 ){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
// Both the encrypt and the decrypt are done 8 bytes at a time
if (encrypt) {
for (i=0; i<in_data_len; i=i+8) {
memcpy(in_key_data, in_data+i, 8);
des_ecb_encrypt(&in_key_data, &out_key_data, des_key2, DES_ENCRYPT);
memcpy(out_data+i, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
for(j=0; j < in_data_len; j=j+8) {
memcpy(in_key_data, in_data+j, 8);
des_ecb_encrypt(&in_key_data, &out_key_data, des_key2, DES_DECRYPT);
memcpy(out_data+j, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
}
CK_RV
token_specific_des_cbc(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len,
CK_BYTE *key_value,
CK_BYTE *init_v,
CK_BYTE encrypt)
{
CK_ULONG rc;
des_cblock ivec;
des_key_schedule des_key2;
const_DES_cblock key_val_SSL;
// Create the key schedule
memcpy(&key_val_SSL, key_value, 8);
des_set_key_unchecked(&key_val_SSL, des_key2);
memcpy(&ivec, init_v, 8);
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % 8 ){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
if ( encrypt){
des_ncbc_encrypt(in_data, out_data, in_data_len, des_key2, &ivec, DES_ENCRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
des_ncbc_encrypt(in_data, out_data, in_data_len, des_key2, &ivec, DES_DECRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
}
CK_RV
token_specific_tdes_ecb(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len,
CK_BYTE *key_value,
CK_BYTE encrypt)
{
CK_RV rc;
unsigned int k, j;
des_key_schedule des_key1;
des_key_schedule des_key2;
des_key_schedule des_key3;
const_des_cblock key_SSL1, key_SSL2, key_SSL3, in_key_data;
des_cblock out_key_data;
// The key as passed is a 24 byte long string containing three des keys
// pick them apart and create the 3 corresponding key schedules
memcpy(&key_SSL1, key_value, 8);
memcpy(&key_SSL2, key_value+8, 8);
memcpy(&key_SSL3, key_value+16, 8);
des_set_key_unchecked(&key_SSL1, des_key1);
des_set_key_unchecked(&key_SSL2, des_key2);
des_set_key_unchecked(&key_SSL3, des_key3);
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % 8 ){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
// the encrypt and decrypt are done 8 bytes at a time
if (encrypt) {
for(k=0;k<in_data_len;k=k+8){
memcpy(in_key_data, in_data+k, 8);
des_ecb3_encrypt((const_DES_cblock *)&in_key_data,
(DES_cblock *)&out_key_data,
des_key1,
des_key2,
des_key3,
DES_ENCRYPT);
memcpy(out_data+k, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
for (j=0;j<in_data_len;j=j+8){
memcpy(in_key_data, in_data+j, 8);
des_ecb3_encrypt((const_DES_cblock *)&in_key_data,
(DES_cblock *)&out_key_data,
des_key1,
des_key2,
des_key3,
DES_DECRYPT);
memcpy(out_data+j, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
}
CK_RV
token_specific_tdes_cbc(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len,
CK_BYTE *key_value,
CK_BYTE *init_v,
CK_BYTE encrypt)
{
CK_RV rc = CKR_OK;
des_key_schedule des_key1;
des_key_schedule des_key2;
des_key_schedule des_key3;
const_des_cblock key_SSL1, key_SSL2, key_SSL3;
des_cblock ivec;
// The key as passed in is a 24 byte string containing 3 keys
// pick it apart and create the key schedules
memcpy(&key_SSL1, key_value, 8);
memcpy(&key_SSL2, key_value+8, 8);
memcpy(&key_SSL3, key_value+16, 8);
des_set_key_unchecked(&key_SSL1, des_key1);
des_set_key_unchecked(&key_SSL2, des_key2);
des_set_key_unchecked(&key_SSL3, des_key3);
memcpy(ivec, init_v, sizeof(ivec));
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % 8 ){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
// Encrypt or decrypt the data
if (encrypt){
des_ede3_cbc_encrypt(in_data,
out_data,
in_data_len,
des_key1,
des_key2,
des_key3,
&ivec,
DES_ENCRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
}else {
des_ede3_cbc_encrypt(in_data,
out_data,
in_data_len,
des_key1,
des_key2,
des_key3,
&ivec,
DES_DECRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
}
/* wrap the 20 bytes of auth data @authData and store in an attribute of the two
* keys.
*/
CK_RV
token_wrap_auth_data(CK_BYTE *authData, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl)
{
CK_RV rc;
CK_ATTRIBUTE *new_attr;
TSS_HKEY hParentKey;
TSS_HENCDATA hEncData;
BYTE *blob;
UINT32 blob_size;
if ((hPrivateLeafKey == NULL_HKEY) && (hPublicLeafKey == NULL_HKEY)) {
LogError("Shouldn't be wrapping auth data in a public path!");
return CKR_FUNCTION_FAILED;
} else if (hPublicLeafKey != NULL_HKEY) {
hParentKey = hPublicLeafKey;
} else {
hParentKey = hPrivateLeafKey;
}
/* create the encrypted data object */
if ((rc = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%lx", rc);
return rc;
}
if ((rc = Tspi_Data_Bind(hEncData, hParentKey, SHA1_HASH_SIZE, authData))) {
LogError("Tspi_Data_Bind failed. rc=0x%lx", rc);
return rc;
}
/* pull the encrypted data out of the encrypted data object */
if ((rc = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
TSS_TSPATTRIB_ENCDATABLOB_BLOB, &blob_size,
&blob))) {
LogError("Tspi_SetAttribData failed. rc=0x%lx", rc);
return rc;
}
if ((rc = build_attribute( CKA_ENC_AUTHDATA, blob, blob_size, &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( publ_tmpl, new_attr );
if ((rc = build_attribute( CKA_ENC_AUTHDATA, blob, blob_size, &new_attr ))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( priv_tmpl, new_attr );
return rc;
}
CK_RV
token_unwrap_auth_data(CK_BYTE *encAuthData, CK_ULONG encAuthDataLen, TSS_HKEY hKey,
BYTE **authData)
{
TSS_RESULT result;
TSS_HENCDATA hEncData;
BYTE *buf;
UINT32 buf_size;
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
TSS_TSPATTRIB_ENCDATABLOB_BLOB, encAuthDataLen,
encAuthData))) {
LogError("Tspi_SetAttribData failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* unbind the data, receiving the plaintext back */
if ((result = Tspi_Data_Unbind(hEncData, hKey, &buf_size, &buf))) {
LogError("Tspi_Data_Unbind failed: rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if (buf_size != SHA1_HASH_SIZE) {
LogError("auth data decrypt error.");
return CKR_FUNCTION_FAILED;
}
*authData = buf;
return CKR_OK;
}
#if 0
// convert from the local PKCS11 template representation to
// the underlying requirement
// returns the pointer to the local key representation
CK_BYTE *
rsa_convert_public_key(OBJECT *key_obj)
{
CK_ATTRIBUTE *modulus = NULL;
CK_BYTE *ret;
CK_RV rc;
rc = template_attribute_find( key_obj->template, CKA_MODULUS, &modulus );
if (rc == FALSE) {
return NULL;
}
ret = malloc(modulus->ulValueLen);
if (ret == NULL) {
LogError("Out of memory.");
return NULL;
}
memcpy(ret, modulus->pValue, modulus->ulValueLen);
return ret;
}
#endif
CK_RV
token_specific_rsa_generate_keypair( TEMPLATE * publ_tmpl,
TEMPLATE * priv_tmpl )
{
CK_ATTRIBUTE *publ_exp = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_ULONG mod_bits = 0;
CK_BBOOL flag;
CK_RV rc;
CK_BYTE tpm_pubexp[] = { 0, 1, 0, 1 };
TSS_FLAG initFlags = 0;
BYTE authHash[SHA1_HASH_SIZE];
BYTE *authData = NULL;
TSS_HKEY hKey = NULL_HKEY;
TSS_HKEY hParentKey = NULL_HKEY;
TSS_RESULT result;
UINT32 ulBlobLen;
BYTE *rgbBlob;
/* Make sure the public exponent is usable */
if ((util_check_public_exponent(publ_tmpl))) {
LogError("Invalid public exponent");
return CKR_TEMPLATE_INCONSISTENT;
}
flag = template_attribute_find( publ_tmpl, CKA_MODULUS_BITS, &attr );
if (!flag){
st_err_log(48, __FILE__, __LINE__);
return CKR_TEMPLATE_INCOMPLETE; // should never happen
}
mod_bits = *(CK_ULONG *)attr->pValue;
if ((initFlags = util_get_keysize_flag(mod_bits)) == 0) {
st_err_log(19, __FILE__, __LINE__);
return CKR_KEY_SIZE_RANGE;
}
/* If we're not logged in, hPrivateLeafKey and hPublicLeafKey should be NULL */
if ((hPrivateLeafKey == NULL_HKEY) && (hPublicLeafKey == NULL_HKEY)) {
/* public session, wrap key with the PRK */
initFlags |= TSS_KEY_TYPE_LEGACY | TSS_KEY_NO_AUTHORIZATION | TSS_KEY_MIGRATABLE;
if ((result = token_load_public_root_key())) {
LogError("token_load_public_root_key failed. rc=%x", result);
return CKR_FUNCTION_FAILED;
}
hParentKey = hPublicRootKey;
} else if (hPrivateLeafKey != NULL_HKEY) {
/* logged in USER session */
initFlags |= TSS_KEY_TYPE_LEGACY | TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE;
/* get a random SHA1 hash for the auth data */
if ((rc = token_rng(authHash, SHA1_HASH_SIZE))) {
LogError("token_rng failed. rc=%lx", rc);
return CKR_FUNCTION_FAILED;
}
authData = authHash;
hParentKey = hPrivateRootKey;
} else {
/* logged in SO session */
initFlags |= TSS_KEY_TYPE_LEGACY | TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE;
/* get a random SHA1 hash for the auth data */
if ((rc = token_rng(authHash, SHA1_HASH_SIZE))) {
LogError("token_rng failed. rc=0x%lx", rc);
return CKR_FUNCTION_FAILED;
}
authData = authHash;
hParentKey = hPublicRootKey;
}
if ((result = tss_generate_key(initFlags, authData, hParentKey, &hKey))) {
LogError("tss_generate_key returned 0x%x", result);
return result;
}
if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB,
&ulBlobLen, &rgbBlob))) {
LogError("Tspi_GetAttribData failed with rc: 0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
return rc;
}
template_update_attribute( priv_tmpl, attr );
if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen, &attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
return rc;
}
template_update_attribute( publ_tmpl, attr );
Tspi_Context_FreeMemory(tspContext, rgbBlob);
/* grab the public key to put into the public key object */
if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &ulBlobLen,
&rgbBlob))) {
LogError("Tspi_GetAttribData failed with rc: 0x%x", result);
return result;
}
/* add the public key blob to the object template */
if ((rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
return rc;
}
template_update_attribute( publ_tmpl, attr );
/* add the public key blob to the object template */
if ((rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr))) {
st_err_log(84, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, rgbBlob);
return rc;
}
template_update_attribute( priv_tmpl, attr );
Tspi_Context_FreeMemory(tspContext, rgbBlob);
/* put the public exponent into the private key object */
if ((rc = build_attribute(CKA_PUBLIC_EXPONENT, tpm_pubexp,
sizeof(tpm_pubexp), &attr))) {
st_err_log(84, __FILE__, __LINE__);
return rc;
}
template_update_attribute( priv_tmpl, attr );
/* wrap the authdata and put it into an object */
if (authData != NULL) {
if ((rc = token_wrap_auth_data(authData, publ_tmpl, priv_tmpl))) {
LogError("token_wrap_auth_data failed with rc: 0x%lx", rc);
}
}
return rc;
}
CK_RV
token_rsa_load_key( OBJECT * key_obj, TSS_HKEY * phKey )
{
TSS_RESULT result;
TSS_HPOLICY hPolicy = NULL_HPOLICY;
TSS_HKEY hParentKey;
BYTE *authData = NULL;
CK_ATTRIBUTE *attr;
CK_RV rc;
CK_OBJECT_HANDLE handle;
if (hPrivateLeafKey != NULL_HKEY) {
hParentKey = hPrivateRootKey;
} else {
if ((result = token_load_public_root_key())) {
LogError("token_load_public_root_key failed. rc=%x", result);
return CKR_FUNCTION_FAILED;
}
hParentKey = hPublicRootKey;
}
if ((rc = template_attribute_find( key_obj->template, CKA_IBM_OPAQUE, &attr )) == FALSE) {
/* if the key blob wasn't found, then try to wrap the key */
rc = object_mgr_find_in_map2(key_obj, &handle);
if (rc != CKR_OK)
return CKR_FUNCTION_FAILED;
if ((rc = token_load_key(handle, hParentKey, NULL, phKey))) {
LogError("token_load_key failed. rc=0x%lx", rc);
return rc;
}
/* try again to get the CKA_IBM_OPAQUE attr */
if ((rc = template_attribute_find( key_obj->template, CKA_IBM_OPAQUE, &attr )) == FALSE)
{
LogError("Could not find key blob");
return rc;
}
}
if ((result = Tspi_Context_LoadKeyByBlob(tspContext, hParentKey, attr->ulValueLen,
attr->pValue, phKey))) {
LogError("Tspi_Context_LoadKeyByBlob failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* auth data may be required */
if (template_attribute_find( key_obj->template, CKA_ENC_AUTHDATA, &attr) == TRUE && attr) {
if ((hPrivateLeafKey == NULL_HKEY) && (hPublicLeafKey == NULL_HKEY)) {
LogError("Shouldn't be in a public session here");
return CKR_FUNCTION_FAILED;
} else if (hPublicLeafKey != NULL_HKEY) {
hParentKey = hPublicLeafKey;
} else {
hParentKey = hPrivateLeafKey;
}
if ((result = token_unwrap_auth_data(attr->pValue, attr->ulValueLen, hParentKey, &authData))) {
LogError("token_unwrap_auth_data: 0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_GetPolicyObject(*phKey, TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_GetPolicyObject: 0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* If the policy handle returned is the same as the context's default policy, then
* a new policy must be created and assigned to the key. Otherwise, just set the
* secret in the policy */
if (hPolicy == hDefaultPolicy) {
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_POLICY,
TSS_POLICY_USAGE, &hPolicy))) {
LogError("Tspi_Context_CreateObject: 0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
SHA1_HASH_SIZE, authData))) {
LogError("Tspi_Policy_SetSecret failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Policy_AssignToObject(hPolicy, *phKey))) {
LogError("Tspi_Policy_AssignToObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
} else if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
SHA1_HASH_SIZE, authData))) {
LogError("Tspi_Policy_SetSecret failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
Tspi_Context_FreeMemory(tspContext, authData);
}
return CKR_OK;
}
/* Convert from the local PKCS11 template representation to the underlying requirement
* returns the pointer to the local key representation */
void *
rsa_convert_public_key( OBJECT * key_obj )
{
CK_BBOOL rc;
CK_ATTRIBUTE * modulus = NULL;
CK_ATTRIBUTE * pub_exp = NULL;
RSA *rsa;
BIGNUM *bn_mod, *bn_exp;
rc = template_attribute_find( key_obj->template, CKA_MODULUS, &modulus );
rc &= template_attribute_find( key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp );
if (rc == FALSE) {
return NULL;
}
// Create an RSA key struct to return
rsa = RSA_new();
if (rsa == NULL)
return NULL;
RSA_blinding_off(rsa);
// Create and init BIGNUM structs to stick in the RSA struct
bn_mod = BN_new();
bn_exp = BN_new();
if (bn_exp == NULL || bn_mod == NULL) {
if (bn_mod) free(bn_mod);
if (bn_exp) free(bn_exp);
RSA_free(rsa);
return NULL;
}
// Convert from strings to BIGNUMs and stick them in the RSA struct
BN_bin2bn((unsigned char *)modulus->pValue, modulus->ulValueLen, bn_mod);
rsa->n = bn_mod;
BN_bin2bn((unsigned char *)pub_exp->pValue, pub_exp->ulValueLen, bn_exp);
rsa->e = bn_exp;
return (void *)rsa;
}
void *
rsa_convert_private_key(OBJECT *key_obj)
{
CK_ATTRIBUTE * attr = NULL;
CK_ATTRIBUTE * modulus = NULL;
CK_ATTRIBUTE * priv_exp = NULL;
CK_ATTRIBUTE * prime1 = NULL;
CK_ATTRIBUTE * prime2 = NULL;
CK_ATTRIBUTE * exp1 = NULL;
CK_ATTRIBUTE * exp2 = NULL;
CK_ATTRIBUTE * coeff = NULL;
CK_BBOOL rc;
RSA *rsa;
BIGNUM *bn_mod, *bn_priv_exp, *bn_p1, *bn_p2, *bn_e1, *bn_e2, *bn_cf;
rc = template_attribute_find( key_obj->template, CKA_MODULUS, &modulus );
rc &= template_attribute_find( key_obj->template, CKA_PRIVATE_EXPONENT, &priv_exp );
rc &= template_attribute_find( key_obj->template, CKA_PRIME_1, &prime1 );
rc &= template_attribute_find( key_obj->template, CKA_PRIME_2, &prime2 );
rc &= template_attribute_find( key_obj->template, CKA_EXPONENT_1, &exp1 );
rc &= template_attribute_find( key_obj->template, CKA_EXPONENT_2, &exp2 );
rc &= template_attribute_find( key_obj->template, CKA_COEFFICIENT, &coeff );
if ( !prime2 && !modulus ){
return NULL;
}
// Create and init all the RSA and BIGNUM structs we need.
rsa = RSA_new();
if (rsa == NULL)
return NULL;
RSA_blinding_off(rsa);
bn_mod = BN_new();
bn_priv_exp = BN_new();
bn_p1 = BN_new();
bn_p2 = BN_new();
bn_e1 = BN_new();
bn_e2 = BN_new();
bn_cf = BN_new();
if ((bn_cf == NULL) || (bn_e2 == NULL) || (bn_e1 == NULL) ||
(bn_p2 == NULL) || (bn_p1 == NULL) || (bn_priv_exp == NULL) ||
(bn_mod == NULL))
{
if (rsa) RSA_free(rsa);
if (bn_mod) BN_free(bn_mod);
if (bn_priv_exp) BN_free(bn_priv_exp);
if (bn_p1) BN_free(bn_p1);
if (bn_p2) BN_free(bn_p2);
if (bn_e1) BN_free(bn_e1);
if (bn_e2) BN_free(bn_e2);
if (bn_cf) BN_free(bn_cf);
return NULL;
}
// CRT key?
if ( prime1){
if (!prime2 || !exp1 ||!exp2 || !coeff) {
return NULL;
}
// Even though this is CRT key, OpenSSL requires the
// modulus and exponents filled in or encrypt and decrypt will
// not work
BN_bin2bn((unsigned char *)modulus->pValue, modulus->ulValueLen, bn_mod);
rsa->n = bn_mod;
BN_bin2bn((unsigned char *)priv_exp->pValue, priv_exp->ulValueLen, bn_priv_exp);
rsa->d = bn_priv_exp;
BN_bin2bn((unsigned char *)prime1->pValue, prime1->ulValueLen, bn_p1);
rsa->p = bn_p1;
BN_bin2bn((unsigned char *)prime2->pValue, prime2->ulValueLen, bn_p2);
rsa->q = bn_p2;
BN_bin2bn((unsigned char *)exp1->pValue, exp1->ulValueLen, bn_e1);
rsa->dmp1 = bn_e1;
BN_bin2bn((unsigned char *)exp2->pValue, exp2->ulValueLen, bn_e2);
rsa->dmq1 = bn_e2;
BN_bin2bn((unsigned char *)coeff->pValue, coeff->ulValueLen, bn_cf);
rsa->iqmp = bn_cf;
return rsa;
} else { // must be a non-CRT key
if (!priv_exp) {
return NULL;
}
BN_bin2bn((unsigned char *)modulus->pValue, modulus->ulValueLen, bn_mod);
rsa->n = bn_mod;
BN_bin2bn((unsigned char *)priv_exp->pValue, priv_exp->ulValueLen, bn_priv_exp);
rsa->d = bn_priv_exp;
}
return (void *)rsa;
}
CK_RV
token_rsa_sw_encrypt(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
OBJECT * key_obj )
{
CK_RV rc;
RSA *rsa;
// Convert the local representation to an OpenSSL representation
if ((rsa = (RSA *)rsa_convert_public_key(key_obj)) == NULL) {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_HOST_MEMORY;
}
// Do an RSA public encryption
rc = RSA_public_encrypt(in_data_len, in_data, out_data, rsa, RSA_PKCS1_PADDING);
if (rc != 0) {
*out_data_len = rc;
rc = CKR_OK;
} else {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
DEBUG_openssl_print_errors();
rc = CKR_FUNCTION_FAILED;
}
RSA_free(rsa);
return rc;
}
CK_RV
token_rsa_sw_decrypt(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
OBJECT * key_obj)
{
CK_RV rv;
int rc;
RSA *rsa;
// Convert the local key representation to an RSA key representaion
if ((rsa = (RSA *)rsa_convert_private_key(key_obj)) == NULL) {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_HOST_MEMORY;
}
// Do the private decryption
rc = RSA_private_decrypt(in_data_len, in_data, out_data, rsa, RSA_PKCS1_PADDING);
if (rc > 0) {
*out_data_len = rc;
rv = CKR_OK;
} else {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
DEBUG_openssl_print_errors();
rv = CKR_FUNCTION_FAILED;
}
RSA_free(rsa);
return rv;
}
CK_RV
token_rsa_sw_sign(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
OBJECT * key_obj)
{
CK_RV rv;
RSA *rsa;
int nid = 0, in_len, rc;
if (in_data_len > UINT_MAX || *out_data_len > UINT_MAX) {
in_len = UINT_MAX;
} else {
in_len = in_data_len;
}
// Convert the local key representation to an RSA key representaion
if ((rsa = (RSA *)rsa_convert_private_key(key_obj)) == NULL) {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
DEBUG_openssl_print_errors();
return CKR_HOST_MEMORY;
}
rc = RSA_private_encrypt(in_len, in_data, out_data, rsa, RSA_PKCS1_PADDING);
if (rc > *out_data_len) {
rv = CKR_BUFFER_TOO_SMALL;
} else if (rc != -1) {
*out_data_len = rc;
rv = CKR_OK;
} else {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
DEBUG_openssl_print_errors();
rv = CKR_FUNCTION_FAILED;
}
RSA_free(rsa);
return rv;
}
CK_RV
token_rsa_sw_verify(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * sig,
CK_ULONG sig_len,
OBJECT * key_obj)
{
CK_RV rc;
RSA *rsa;
int nid = 0, in_len, out_len;
char tmp[256];
if (in_data_len > UINT_MAX || sig_len > UINT_MAX) {
in_len = out_len = UINT_MAX;
} else {
in_len = in_data_len;
out_len = sig_len;
}
// Convert the local key representation to an RSA key representaion
if ((rsa = (RSA *)rsa_convert_public_key(key_obj)) == NULL) {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_HOST_MEMORY;
}
rc = RSA_public_decrypt(out_len, sig, tmp, rsa, RSA_PKCS1_PADDING);
if (rc == in_len && !memcmp(tmp, in_data, in_len)) {
rc = CKR_OK;
} else {
rc = CKR_SIGNATURE_INVALID;
}
RSA_free(rsa);
return rc;
}
CK_RV
token_specific_rsa_decrypt( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
OBJECT * key_obj )
{
CK_RV rc;
TSS_RESULT result;
TSS_HKEY hKey;
TSS_HENCDATA hEncData = NULL_HENCDATA;
UINT32 buf_size = 0;
BYTE *buf = NULL;
if ((rc = token_rsa_load_key(key_obj, &hKey))) {
LogDebug("Not a TPM-based key. Falling back to software");
return token_rsa_sw_decrypt(in_data, in_data_len, out_data, out_data_len, key_obj);
}
/* push the data into the encrypted data object */
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
TSS_TSPATTRIB_ENCDATABLOB_BLOB, in_data_len, in_data))) {
LogError("Tspi_SetAttribData failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* unbind the data, receiving the plaintext back */
LogError("unbinding data with size: %ld", in_data_len);
if ((result = Tspi_Data_Unbind(hEncData, hKey, &buf_size, &buf))) {
LogError("Tspi_Data_Unbind failed: 0x%x", result);
return CKR_FUNCTION_FAILED;
}
if (*out_data_len < buf_size) {
st_err_log(111, __FILE__, __LINE__);
Tspi_Context_FreeMemory(tspContext, buf);
return CKR_BUFFER_TOO_SMALL;
}
memcpy(out_data, buf, buf_size);
*out_data_len = buf_size;
Tspi_Context_FreeMemory(tspContext, buf);
return CKR_OK;
}
CK_RV
token_specific_rsa_verify( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * sig,
CK_ULONG sig_len,
OBJECT * key_obj )
{
TSS_RESULT result;
TSS_HHASH hHash;
TSS_HKEY hKey;
CK_RV rc;
if ((rc = token_rsa_load_key(key_obj, &hKey))) {
LogDebug("Not a TPM-based key. Falling back to software");
return token_rsa_sw_verify(in_data, in_data_len, sig, sig_len, key_obj);
}
/* Create the hash object we'll use to sign */
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_HASH,
TSS_HASH_OTHER, &hHash))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* Insert the data into the hash object */
if ((result = Tspi_Hash_SetHashValue(hHash, in_data_len, in_data))) {
LogError("Tspi_Hash_SetHashValue failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* Verify */
result = Tspi_Hash_VerifySignature(hHash, hKey, sig_len, sig);
if (result != TSS_SUCCESS &&
TPMTOK_TSS_ERROR_CODE(result) != TSS_E_FAIL) {
LogError("Tspi_Hash_VerifySignature failed. rc=0x%x", result);
}
if (TPMTOK_TSS_ERROR_CODE(result) == TSS_E_FAIL) {
rc = CKR_SIGNATURE_INVALID;
} else {
rc = CKR_OK;
}
return rc;
}
CK_RV
token_specific_rsa_sign(CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
OBJECT * key_obj )
{
TSS_RESULT result;
TSS_HHASH hHash;
BYTE *sig;
UINT32 sig_len;
TSS_HKEY hKey;
CK_RV rc;
if ((rc = token_rsa_load_key(key_obj, &hKey))) {
LogDebug("Not a TPM-based key. Falling back to software");
return token_rsa_sw_sign(in_data, in_data_len, out_data, out_data_len, key_obj);
}
/* Create the hash object we'll use to sign */
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_HASH,
TSS_HASH_OTHER, &hHash))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* Insert the data into the hash object */
if ((result = Tspi_Hash_SetHashValue(hHash, in_data_len, in_data))) {
LogError("Tspi_Hash_SetHashValue failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
/* Sign */
if ((result = Tspi_Hash_Sign(hHash, hKey, &sig_len, &sig))) {
LogError("Tspi_Hash_Sign failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if (sig_len > *out_data_len) {
LogError("%s: Error: Buffer too small to hold result.", __FUNCTION__);
Tspi_Context_FreeMemory(tspContext, sig);
return CKR_BUFFER_TOO_SMALL;
}
memcpy(out_data, sig, sig_len);
*out_data_len = sig_len;
Tspi_Context_FreeMemory(tspContext, sig);
return CKR_OK;
}
CK_RV
token_specific_rsa_encrypt( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
OBJECT * key_obj )
{
TSS_RESULT result;
TSS_HENCDATA hEncData;
BYTE *dataBlob;
UINT32 dataBlobSize;
TSS_HKEY hKey;
CK_RV rc;
if ((rc = token_rsa_load_key(key_obj, &hKey))) {
LogDebug("Not a TPM-based key. Falling back to software");
return token_rsa_sw_encrypt(in_data, in_data_len, out_data, out_data_len, key_obj);
}
if ((result = Tspi_Context_CreateObject(tspContext, TSS_OBJECT_TYPE_ENCDATA,
TSS_ENCDATA_BIND, &hEncData))) {
LogError("Tspi_Context_CreateObject failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_Data_Bind(hEncData, hKey, in_data_len, in_data))) {
LogError("Tspi_Data_Bind failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if ((result = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
TSS_TSPATTRIB_ENCDATABLOB_BLOB, &dataBlobSize, &dataBlob))) {
LogError("Tspi_SetAttribData failed. rc=0x%x", result);
return CKR_FUNCTION_FAILED;
}
if (dataBlobSize > *out_data_len) {
LogError("CKR_DATA_LEN_RANGE");
Tspi_Context_FreeMemory(tspContext, dataBlob);
return CKR_DATA_LEN_RANGE;
}
memcpy(out_data, dataBlob, dataBlobSize);
*out_data_len = dataBlobSize;
Tspi_Context_FreeMemory(tspContext, dataBlob);
return CKR_OK;
}
CK_RV
token_specific_aes_key_gen(CK_BYTE *key, CK_ULONG len)
{
return token_rng(key, len);
}
CK_RV
token_specific_aes_ecb( CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len,
CK_BYTE *key_value,
CK_ULONG key_len,
CK_BYTE encrypt)
{
AES_KEY ssl_aes_key;
unsigned int i;
/* There's a previous check that in_data_len % AES_BLOCK_SIZE == 0,
* so this is fine */
CK_ULONG loops = (CK_ULONG)(in_data_len/AES_BLOCK_SIZE);
memset( &ssl_aes_key, 0, sizeof(AES_KEY));
// AES_ecb_encrypt encrypts only a single block, so we have to break up the
// input data here
if (encrypt) {
AES_set_encrypt_key((unsigned char *)key_value, (key_len*8), &ssl_aes_key);
for( i=0; i<loops; i++ ) {
AES_ecb_encrypt((unsigned char *)in_data + (i*AES_BLOCK_SIZE),
(unsigned char *)out_data + (i*AES_BLOCK_SIZE),
&ssl_aes_key,
AES_ENCRYPT);
}
} else {
AES_set_decrypt_key((unsigned char *)key_value, (key_len*8), &ssl_aes_key);
for( i=0; i<loops; i++ ) {
AES_ecb_encrypt((unsigned char *)in_data + (i*AES_BLOCK_SIZE),
(unsigned char *)out_data + (i*AES_BLOCK_SIZE),
&ssl_aes_key,
AES_DECRYPT);
}
}
*out_data_len = in_data_len;
return CKR_OK;
}
CK_RV
token_specific_aes_cbc( CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len,
CK_BYTE *key_value,
CK_ULONG key_len,
CK_BYTE *init_v,
CK_BYTE encrypt)
{
AES_KEY ssl_aes_key;
memset( &ssl_aes_key, 0, sizeof(AES_KEY));
// AES_cbc_encrypt chunks the data into AES_BLOCK_SIZE blocks, unlike
// AES_ecb_encrypt, so no looping required.
if (encrypt) {
AES_set_encrypt_key((unsigned char *)key_value, (key_len*8), &ssl_aes_key);
AES_cbc_encrypt((unsigned char *)in_data, (unsigned char *)out_data,
in_data_len, &ssl_aes_key,
init_v, AES_ENCRYPT);
} else {
AES_set_decrypt_key((unsigned char *)key_value, (key_len*8), &ssl_aes_key);
AES_cbc_encrypt((unsigned char *)in_data, (unsigned char *)out_data,
in_data_len, &ssl_aes_key,
init_v, AES_DECRYPT);
}
*out_data_len = in_data_len;
return CKR_OK;
}
#ifndef NODH
/* Begin code contributed by Corrent corp. */
// This computes DH shared secret, where:
// Output: z is computed shared secret
// Input: y is other party's public key
// x is private key
// p is prime
// All length's are in number of bytes. All data comes in as Big Endian.
CK_RV
token_specific_dh_pkcs_derive( CK_BYTE *z,
CK_ULONG *z_len,
CK_BYTE *y,
CK_ULONG y_len,
CK_BYTE *x,
CK_ULONG x_len,
CK_BYTE *p,
CK_ULONG p_len)
{
CK_RV rc ;
BIGNUM *bn_z, *bn_y, *bn_x, *bn_p ;
BN_CTX *ctx;
// Create and Init the BIGNUM structures.
bn_y = BN_new() ;
bn_x = BN_new() ;
bn_p = BN_new() ;
bn_z = BN_new() ;
if (bn_z == NULL || bn_p == NULL || bn_x == NULL || bn_y == NULL) {
if (bn_y) BN_free(bn_y);
if (bn_x) BN_free(bn_x);
if (bn_p) BN_free(bn_p);
if (bn_z) BN_free(bn_z);
st_err_log(1, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
BN_init(bn_y) ;
BN_init(bn_x) ;
BN_init(bn_p) ;
// Initialize context
ctx=BN_CTX_new();
if (ctx == NULL)
{
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// Add data into these new BN structures
BN_bin2bn((char *)y, y_len, bn_y);
BN_bin2bn((char *)x, x_len, bn_x);
BN_bin2bn((char *)p, p_len, bn_p);
rc = BN_mod_exp(bn_z,bn_y,bn_x,bn_p,ctx);
if (rc == 0)
{
BN_free(bn_z);
BN_free(bn_y);
BN_free(bn_x);
BN_free(bn_p);
BN_CTX_free(ctx);
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
*z_len = BN_num_bytes(bn_z);
BN_bn2bin(bn_z, z);
BN_free(bn_z);
BN_free(bn_y);
BN_free(bn_x);
BN_free(bn_p);
BN_CTX_free(ctx);
return CKR_OK;
} /* end token_specific_dh_pkcs_derive() */
// This computes DH key pair, where:
// Output: priv_tmpl is generated private key
// pub_tmpl is computed public key
// Input: pub_tmpl is public key (prime and generator)
// All length's are in number of bytes. All data comes in as Big Endian.
CK_RV
token_specific_dh_pkcs_key_pair_gen( TEMPLATE * publ_tmpl,
TEMPLATE * priv_tmpl )
{
CK_BBOOL rc;
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *temp_attr = NULL ;
CK_ATTRIBUTE *value_bits_attr = NULL;
CK_BYTE *temp_byte;
CK_ULONG temp_bn_len ;
DH *dh ;
BIGNUM *bn_p ;
BIGNUM *bn_g ;
BIGNUM *temp_bn ;
rc = template_attribute_find( publ_tmpl, CKA_PRIME, &prime_attr );
rc &= template_attribute_find( publ_tmpl, CKA_BASE, &base_attr );
if (rc == FALSE) {
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if ((prime_attr->ulValueLen > 256) || (prime_attr->ulValueLen < 64))
{
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
dh = DH_new() ;
if (dh == NULL)
{
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// Create and init BIGNUM structs to stick in the DH struct
bn_p = BN_new();
bn_g = BN_new();
if (bn_g == NULL || bn_p == NULL) {
if (bn_g) BN_free(bn_g);
if (bn_p) BN_free(bn_p);
st_err_log(1, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
BN_init(bn_p);
BN_init(bn_g);
// Convert from strings to BIGNUMs and stick them in the DH struct
BN_bin2bn((char *)prime_attr->pValue, prime_attr->ulValueLen, bn_p);
dh->p = bn_p;
BN_bin2bn((char *)base_attr->pValue, base_attr->ulValueLen, bn_g);
dh->g = bn_g;
// Generate the DH Key
if (!DH_generate_key(dh))
{
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// Extract the public and private key components from the DH struct,
// and insert them in the publ_tmpl and priv_tmpl
//
// pub_key
//
//temp_bn = BN_new();
temp_bn = dh->pub_key;
temp_bn_len = BN_num_bytes(temp_bn);
temp_byte = malloc(temp_bn_len);
temp_bn_len = BN_bn2bin(temp_bn, temp_byte);
rc = build_attribute( CKA_VALUE, temp_byte, temp_bn_len, &temp_attr ); // in bytes
if (rc != CKR_OK)
{
st_err_log(84, __FILE__, __LINE__);
return CKR_FUNCTION_FAILED;
}
template_update_attribute( publ_tmpl, temp_attr );
free(temp_byte);
//
// priv_key
//
//temp_bn = BN_new();
temp_bn = dh->priv_key;
temp_bn_len = BN_num_bytes(temp_bn);
temp_byte = malloc(temp_bn_len);
temp_bn_len = BN_bn2bin(temp_bn, temp_byte);
rc = build_attribute( CKA_VALUE, temp_byte, temp_bn_len, &temp_attr ); // in bytes
if (rc != CKR_OK)
{
st_err_log(84, __FILE__, __LINE__);
return CKR_FUNCTION_FAILED;
}
template_update_attribute( priv_tmpl, temp_attr );
free(temp_byte);
// Update CKA_VALUE_BITS attribute in the private key
value_bits_attr = (CK_ATTRIBUTE *)malloc( sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG) );
value_bits_attr->type = CKA_VALUE_BITS;
value_bits_attr->ulValueLen = sizeof(CK_ULONG);
value_bits_attr->pValue = (CK_BYTE *)value_bits_attr + sizeof(CK_ATTRIBUTE);
*(CK_ULONG *)value_bits_attr->pValue = 8*temp_bn_len;
template_update_attribute( priv_tmpl, value_bits_attr );
// Add prime and base to the private key template
rc = build_attribute( CKA_PRIME,(char *)prime_attr->pValue,
prime_attr->ulValueLen, &temp_attr ); // in bytes
if (rc != CKR_OK)
{
st_err_log(84, __FILE__, __LINE__);
return CKR_FUNCTION_FAILED;
}
template_update_attribute( priv_tmpl, temp_attr );
rc = build_attribute( CKA_BASE,(char *)base_attr->pValue,
base_attr->ulValueLen, &temp_attr ); // in bytes
if (rc != CKR_OK)
{
st_err_log(84, __FILE__, __LINE__);
return CKR_FUNCTION_FAILED;
}
template_update_attribute( priv_tmpl, temp_attr );
// Cleanup DH key
DH_free(dh) ;
return CKR_OK ;
}
#endif