diff options
Diffstat (limited to 'src/tpm2/DuplicationCommands.c')
-rw-r--r-- | src/tpm2/DuplicationCommands.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/src/tpm2/DuplicationCommands.c b/src/tpm2/DuplicationCommands.c new file mode 100644 index 0000000..525ecf7 --- /dev/null +++ b/src/tpm2/DuplicationCommands.c @@ -0,0 +1,352 @@ +/********************************************************************************/ +/* */ +/* Duplication Commands */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: DuplicationCommands.c 1490 2019-07-26 21:13:22Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "Duplicate_fp.h" +#if CC_Duplicate // Conditional expansion of this file +#include "Object_spt_fp.h" +TPM_RC +TPM2_Duplicate( + Duplicate_In *in, // IN: input parameter list + Duplicate_Out *out // OUT: output parameter list + ) +{ + TPM_RC result = TPM_RC_SUCCESS; + TPMT_SENSITIVE sensitive; + UINT16 innerKeySize = 0; // encrypt key size for inner wrap + OBJECT *object; + OBJECT *newParent; + TPM2B_DATA data; + // Input Validation + // Get duplicate object pointer + object = HandleToObject(in->objectHandle); + // Get new parent + newParent = HandleToObject(in->newParentHandle); + // duplicate key must have fixParent bit CLEAR. + if(IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, fixedParent)) + return TPM_RCS_ATTRIBUTES + RC_Duplicate_objectHandle; + // Do not duplicate object with NULL nameAlg + if(object->publicArea.nameAlg == TPM_ALG_NULL) + return TPM_RCS_TYPE + RC_Duplicate_objectHandle; + // new parent key must be a storage object or TPM_RH_NULL + if(in->newParentHandle != TPM_RH_NULL + && !ObjectIsStorage(in->newParentHandle)) + return TPM_RCS_TYPE + RC_Duplicate_newParentHandle; + // If the duplicated object has encryptedDuplication SET, then there must be + // an inner wrapper and the new parent may not be TPM_RH_NULL + if(IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, + encryptedDuplication)) + { + if(in->symmetricAlg.algorithm == TPM_ALG_NULL) + return TPM_RCS_SYMMETRIC + RC_Duplicate_symmetricAlg; + if(in->newParentHandle == TPM_RH_NULL) + return TPM_RCS_HIERARCHY + RC_Duplicate_newParentHandle; + } + if(in->symmetricAlg.algorithm == TPM_ALG_NULL) + { + // if algorithm is TPM_ALG_NULL, input key size must be 0 + if(in->encryptionKeyIn.t.size != 0) + return TPM_RCS_SIZE + RC_Duplicate_encryptionKeyIn; + } + else + { + // Get inner wrap key size + innerKeySize = in->symmetricAlg.keyBits.sym; + // If provided the input symmetric key must match the size of the algorithm + if(in->encryptionKeyIn.t.size != 0 + && in->encryptionKeyIn.t.size != (innerKeySize + 7) / 8) + return TPM_RCS_SIZE + RC_Duplicate_encryptionKeyIn; + } + // Command Output + if(in->newParentHandle != TPM_RH_NULL) + { + // Make encrypt key and its associated secret structure. A TPM_RC_KEY + // error may be returned at this point + out->outSymSeed.t.size = sizeof(out->outSymSeed.t.secret); + result = CryptSecretEncrypt(newParent, DUPLICATE_STRING, &data, + &out->outSymSeed); + if(result != TPM_RC_SUCCESS) + return result; + } + else + { + // Do not apply outer wrapper + data.t.size = 0; + out->outSymSeed.t.size = 0; + } + // Copy sensitive area + sensitive = object->sensitive; + // Prepare output private data from sensitive. + // Note: If there is no encryption key, one will be provided by + // SensitiveToDuplicate(). This is why the assignment of encryptionKeyIn to + // encryptionKeyOut will work properly and is not conditional. + SensitiveToDuplicate(&sensitive, &object->name.b, newParent, + object->publicArea.nameAlg, &data.b, + &in->symmetricAlg, &in->encryptionKeyIn, + &out->duplicate); + out->encryptionKeyOut = in->encryptionKeyIn; + return TPM_RC_SUCCESS; +} +#endif // CC_Duplicate +#include "Tpm.h" +#include "Rewrap_fp.h" +#if CC_Rewrap // Conditional expansion of this file +#include "Object_spt_fp.h" +TPM_RC +TPM2_Rewrap( + Rewrap_In *in, // IN: input parameter list + Rewrap_Out *out // OUT: output parameter list + ) +{ + TPM_RC result = TPM_RC_SUCCESS; + TPM2B_DATA data; // symmetric key + UINT16 hashSize = 0; + TPM2B_PRIVATE privateBlob; // A temporary private blob + // to transit between old + // and new wrappers + // Input Validation + if((in->inSymSeed.t.size == 0 && in->oldParent != TPM_RH_NULL) + || (in->inSymSeed.t.size != 0 && in->oldParent == TPM_RH_NULL)) + return TPM_RCS_HANDLE + RC_Rewrap_oldParent; + if(in->oldParent != TPM_RH_NULL) + { + OBJECT *oldParent = HandleToObject(in->oldParent); + // old parent key must be a storage object + if(!ObjectIsStorage(in->oldParent)) + return TPM_RCS_TYPE + RC_Rewrap_oldParent; + // Decrypt input secret data via asymmetric decryption. A + // TPM_RC_VALUE, TPM_RC_KEY or unmarshal errors may be returned at this + // point + result = CryptSecretDecrypt(oldParent, NULL, DUPLICATE_STRING, + &in->inSymSeed, &data); + if(result != TPM_RC_SUCCESS) + return TPM_RCS_VALUE + RC_Rewrap_inSymSeed; + // Unwrap Outer + result = UnwrapOuter(oldParent, &in->name.b, + oldParent->publicArea.nameAlg, &data.b, + FALSE, + in->inDuplicate.t.size, in->inDuplicate.t.buffer); + if(result != TPM_RC_SUCCESS) + return RcSafeAddToResult(result, RC_Rewrap_inDuplicate); + // Copy unwrapped data to temporary variable, remove the integrity field + hashSize = sizeof(UINT16) + + CryptHashGetDigestSize(oldParent->publicArea.nameAlg); + privateBlob.t.size = in->inDuplicate.t.size - hashSize; + pAssert(privateBlob.t.size <= sizeof(privateBlob.t.buffer)); + MemoryCopy(privateBlob.t.buffer, in->inDuplicate.t.buffer + hashSize, + privateBlob.t.size); + } + else + { + // No outer wrap from input blob. Direct copy. + privateBlob = in->inDuplicate; + } + if(in->newParent != TPM_RH_NULL) + { + OBJECT *newParent; + newParent = HandleToObject(in->newParent); + // New parent must be a storage object + if(!ObjectIsStorage(in->newParent)) + return TPM_RCS_TYPE + RC_Rewrap_newParent; + // Make new encrypt key and its associated secret structure. A + // TPM_RC_VALUE error may be returned at this point if RSA algorithm is + // enabled in TPM + out->outSymSeed.t.size = sizeof(out->outSymSeed.t.secret); + result = CryptSecretEncrypt(newParent, DUPLICATE_STRING, &data, + &out->outSymSeed); + if(result != TPM_RC_SUCCESS) + return result; + // Copy temporary variable to output, reserve the space for integrity + hashSize = sizeof(UINT16) + + CryptHashGetDigestSize(newParent->publicArea.nameAlg); + // Make sure that everything fits into the output buffer + // Note: this is mostly only an issue if there was no outer wrapper on + // 'inDuplicate'. It could be as large as a TPM2B_PRIVATE buffer. If we add + // a digest for an outer wrapper, it won't fit anymore. + if((privateBlob.t.size + hashSize) > sizeof(out->outDuplicate.t.buffer)) + return TPM_RCS_VALUE + RC_Rewrap_inDuplicate; + // Command output + out->outDuplicate.t.size = privateBlob.t.size; + pAssert(privateBlob.t.size + <= sizeof(out->outDuplicate.t.buffer) - hashSize); + MemoryCopy(out->outDuplicate.t.buffer + hashSize, privateBlob.t.buffer, + privateBlob.t.size); + // Produce outer wrapper for output + out->outDuplicate.t.size = ProduceOuterWrap(newParent, &in->name.b, + newParent->publicArea.nameAlg, + &data.b, + FALSE, + out->outDuplicate.t.size, + out->outDuplicate.t.buffer); + } + else // New parent is a null key so there is no seed + { + out->outSymSeed.t.size = 0; + // Copy privateBlob directly + out->outDuplicate = privateBlob; + } + return TPM_RC_SUCCESS; +} +#endif // CC_Rewrap +#include "Tpm.h" +#include "Import_fp.h" +#if CC_Import // Conditional expansion of this file +#include "Object_spt_fp.h" +TPM_RC +TPM2_Import( + Import_In *in, // IN: input parameter list + Import_Out *out // OUT: output parameter list + ) +{ + TPM_RC result = TPM_RC_SUCCESS; + OBJECT *parentObject; + TPM2B_DATA data; // symmetric key + TPMT_SENSITIVE sensitive; + TPM2B_NAME name; + TPMA_OBJECT attributes; + UINT16 innerKeySize = 0; // encrypt key size for inner + // wrapper + // Input Validation + // to save typing + attributes = in->objectPublic.publicArea.objectAttributes; + // FixedTPM and fixedParent must be CLEAR + if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM) + || IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)) + return TPM_RCS_ATTRIBUTES + RC_Import_objectPublic; + // Get parent pointer + parentObject = HandleToObject(in->parentHandle); + if(!ObjectIsParent(parentObject)) + return TPM_RCS_TYPE + RC_Import_parentHandle; + if(in->symmetricAlg.algorithm != TPM_ALG_NULL) + { + // Get inner wrap key size + innerKeySize = in->symmetricAlg.keyBits.sym; + // Input symmetric key must match the size of algorithm. + if(in->encryptionKey.t.size != (innerKeySize + 7) / 8) + return TPM_RCS_SIZE + RC_Import_encryptionKey; + } + else + { + // If input symmetric algorithm is NULL, input symmetric key size must + // be 0 as well + if(in->encryptionKey.t.size != 0) + return TPM_RCS_SIZE + RC_Import_encryptionKey; + // If encryptedDuplication is SET, then the object must have an inner + // wrapper + if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)) + return TPM_RCS_ATTRIBUTES + RC_Import_encryptionKey; + } + // See if there is an outer wrapper + if(in->inSymSeed.t.size != 0) + { + // in->inParentHandle is a parent, but in order to decrypt an outer wrapper, + // it must be able to do key exchange and a symmetric key can't do that. + if(parentObject->publicArea.type == TPM_ALG_SYMCIPHER) + return TPM_RCS_TYPE + RC_Import_parentHandle; + // Decrypt input secret data via asymmetric decryption. TPM_RC_ATTRIBUTES, + // TPM_RC_ECC_POINT, TPM_RC_INSUFFICIENT, TPM_RC_KEY, TPM_RC_NO_RESULT, + // TPM_RC_SIZE, TPM_RC_VALUE may be returned at this point + result = CryptSecretDecrypt(parentObject, NULL, DUPLICATE_STRING, + &in->inSymSeed, &data); + pAssert(result != TPM_RC_BINDING); + if(result != TPM_RC_SUCCESS) + return RcSafeAddToResult(result, RC_Import_inSymSeed); + } + else + { + // If encrytpedDuplication is set, then the object must have an outer + // wrapper + if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)) + return TPM_RCS_ATTRIBUTES + RC_Import_inSymSeed; + data.t.size = 0; + } + // Compute name of object + PublicMarshalAndComputeName(&(in->objectPublic.publicArea), &name); + if(name.t.size == 0) + return TPM_RCS_HASH + RC_Import_objectPublic; + // Retrieve sensitive from private. + // TPM_RC_INSUFFICIENT, TPM_RC_INTEGRITY, TPM_RC_SIZE may be returned here. + result = DuplicateToSensitive(&in->duplicate.b, &name.b, parentObject, + in->objectPublic.publicArea.nameAlg, + &data.b, &in->symmetricAlg, + &in->encryptionKey.b, &sensitive); + if(result != TPM_RC_SUCCESS) + return RcSafeAddToResult(result, RC_Import_duplicate); + // If the parent of this object has fixedTPM SET, then validate this + // object as if it were being loaded so that validation can be skipped + // when it is actually loaded. + if(IS_ATTRIBUTE(parentObject->publicArea.objectAttributes, TPMA_OBJECT, fixedTPM)) + { + result = ObjectLoad(NULL, NULL, &in->objectPublic.publicArea, + &sensitive, RC_Import_objectPublic, RC_Import_duplicate, + NULL); + } + // Command output + if(result == TPM_RC_SUCCESS) + { + // Prepare output private data from sensitive + SensitiveToPrivate(&sensitive, &name, parentObject, + in->objectPublic.publicArea.nameAlg, + &out->outPrivate); + } + return result; +} +#endif // CC_Import |