/********************************************************************************/ /* */ /* High Level Platform Independent Cryptography */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* $Id: tpm_cryptoh.c 4540 2011-04-07 18:51:34Z kgoldman $ */ /* */ /* (c) Copyright IBM Corporation 2006, 2010. */ /* */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions are */ /* met: */ /* */ /* Redistributions of source code must retain the above copyright notice, */ /* this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* Neither the names of the IBM Corporation nor the names of its */ /* contributors may be used to endorse or promote products derived from */ /* this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /********************************************************************************/ #include #include #include #include #include "tpm_admin.h" #include "tpm_auth.h" #include "tpm_crypto.h" #include "tpm_debug.h" #include "tpm_digest.h" #include "tpm_error.h" #include "tpm_io.h" #include "tpm_memory.h" #include "tpm_migration.h" #include "tpm_nonce.h" #include "tpm_key.h" #include "tpm_pcr.h" #include "tpm_process.h" #include "tpm_store.h" #include "tpm_ver.h" #include "tpm_cryptoh.h" /* local prototypes */ static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, uint32_t length0, unsigned char *buffer0, va_list ap); static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC hmac, const TPM_SECRET key, va_list ap); static TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, void **sha1_context, TPM_SIZED_BUFFER *hashData); /* TPM_SIGN_INFO */ /* TPM_SignInfo_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_SignInfo_Init(TPM_SIGN_INFO *tpm_sign_info) { printf(" TPM_SignInfo_Init:\n"); memset(tpm_sign_info->fixed, 0, TPM_SIGN_INFO_FIXED_SIZE); TPM_Nonce_Init(tpm_sign_info->replay); TPM_SizedBuffer_Init(&(tpm_sign_info->data)); return; } /* TPM_SignInfo_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_SignInfo_Store(TPM_STORE_BUFFER *sbuffer, const TPM_SIGN_INFO *tpm_sign_info) { TPM_RESULT rc = 0; printf(" TPM_SignInfo_Store:\n"); /* store the tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SIGNINFO); } /* store the fixed */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, tpm_sign_info->fixed, TPM_SIGN_INFO_FIXED_SIZE); } /* store the replay */ if (rc == 0) { rc = TPM_Nonce_Store(sbuffer, tpm_sign_info->replay); } /* store the dataLen and data */ if (rc == 0) { rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sign_info->data)); } if (rc == 0) { const unsigned char *buffer; uint32_t length; TPM_Sbuffer_Get(sbuffer, &buffer, &length); TPM_PrintAll(" TPM_SignInfo_Store: Buffer", buffer, length); } return rc; } /* TPM_SignInfo_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the sign_info sets pointers to NULL calls TPM_SignInfo_Init to set members back to default values The sign_info itself is not freed */ void TPM_SignInfo_Delete(TPM_SIGN_INFO *tpm_sign_info) { printf(" TPM_SignInfo_Delete:\n"); if (tpm_sign_info != NULL) { TPM_SizedBuffer_Delete(&(tpm_sign_info->data)); TPM_SignInfo_Init(tpm_sign_info); } return; } /* TPM_CERTIFY_INFO */ /* TPM_CertifyInfo_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_CertifyInfo_Init(TPM_CERTIFY_INFO *tpm_certify_info) { printf(" TPM_CertifyInfo_Init:\n"); TPM_StructVer_Init(&(tpm_certify_info->version)); tpm_certify_info->keyUsage = TPM_KEY_UNINITIALIZED; tpm_certify_info->keyFlags = 0; tpm_certify_info->authDataUsage = TPM_AUTH_ALWAYS; TPM_KeyParms_Init(&(tpm_certify_info->algorithmParms)); TPM_Digest_Init(tpm_certify_info->pubkeyDigest); TPM_Nonce_Init(tpm_certify_info->data); tpm_certify_info->parentPCRStatus = TRUE; TPM_SizedBuffer_Init(&(tpm_certify_info->pcrInfo)); tpm_certify_info->tpm_pcr_info = NULL; return; } #if 0 /* TPM_CertifyInfo_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_CertifyInfo_Init() After use, call TPM_CertifyInfo_Delete() to free memory NOTE: Never called. */ TPM_RESULT TPM_CertifyInfo_Load(TPM_CERTIFY_INFO *tpm_certify_info, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; printf(" TPM_CertifyInfo_Load:\n"); /* load version */ if (rc == 0) { rc = TPM_StructVer_Load(&(tpm_certify_info->version), stream, stream_size); } /* check ver immediately to ease debugging */ if (rc == 0) { rc = TPM_StructVer_CheckVer(&(tpm_certify_info->version)); } /* load keyUsage */ if (rc == 0) { rc = TPM_Load16(&(tpm_certify_info->keyUsage), stream, stream_size); } /* load keyFlags */ if (rc == 0) { rc = TPM_KeyFlags_Load(&(tpm_certify_info->keyFlags), stream, stream_size); } /* load authDataUsage */ if (rc == 0) { rc = TPM_Load8(&(tpm_certify_info->authDataUsage), stream, stream_size); } /* load algorithmParms */ if (rc == 0) { rc = TPM_KeyParms_Load(&(tpm_certify_info->algorithmParms), stream, stream_size); } /* load pubkeyDigest */ if (rc == 0) { rc = TPM_Digest_Load(tpm_certify_info->pubkeyDigest, stream, stream_size); } /* load data */ if (rc == 0) { rc = TPM_Nonce_Load(tpm_certify_info->data, stream, stream_size); } /* load parentPCRStatus */ if (rc == 0) { rc = TPM_LoadBool(&(tpm_certify_info->parentPCRStatus), stream, stream_size); } /* load pcrInfo */ if (rc == 0) { rc = TPM_SizedBuffer_Load(&(tpm_certify_info->pcrInfo), stream, stream_size); } /* set TPM_PCR_INFO tpm_pcr_info cache from pcrInfo */ if (rc == 0) { rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_certify_info->tpm_pcr_info), &(tpm_certify_info->pcrInfo)); } return rc; } #endif /* TPM_CertifyInfo_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_CertifyInfo_Store(TPM_STORE_BUFFER *sbuffer, TPM_CERTIFY_INFO *tpm_certify_info) { TPM_RESULT rc = 0; printf(" TPM_CertifyInfo_Store:\n"); /* store version */ if (rc == 0) { rc = TPM_StructVer_Store(sbuffer, &(tpm_certify_info->version)); } /* store keyUsage */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info->keyUsage); } /* store keyFlags */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info->keyFlags); } /* store authDataUsage */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->authDataUsage), sizeof(TPM_AUTH_DATA_USAGE)); } /* store algorithmParms */ if (rc == 0) { rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info->algorithmParms)); } /* store pubkeyDigest */ if (rc == 0) { rc = TPM_Digest_Store(sbuffer, tpm_certify_info->pubkeyDigest); } /* store data */ if (rc == 0) { rc = TPM_Nonce_Store(sbuffer, tpm_certify_info->data); } /* store parentPCRStatus */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->parentPCRStatus), sizeof(TPM_BOOL)); } /* copy cache to pcrInfo */ if (rc == 0) { rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info->pcrInfo), tpm_certify_info->tpm_pcr_info, (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); } /* copy pcrInfo to sbuffer */ if (rc == 0) { rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info->pcrInfo)); } return rc; } /* TPM_CertifyInfo_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_CertifyInfo_Init to set members back to default values The object itself is not freed */ void TPM_CertifyInfo_Delete(TPM_CERTIFY_INFO *tpm_certify_info) { printf(" TPM_CertifyInfo_Delete:\n"); if (tpm_certify_info != NULL) { TPM_KeyParms_Delete(&(tpm_certify_info->algorithmParms)); /* pcrInfo */ TPM_SizedBuffer_Delete(&(tpm_certify_info->pcrInfo)); /* pcr cache */ TPM_PCRInfo_Delete(tpm_certify_info->tpm_pcr_info); free(tpm_certify_info->tpm_pcr_info); TPM_CertifyInfo_Init(tpm_certify_info); } return; } /* TPM_CertifyInfo_Set() fills in tpm_certify_info with the information from the key pointed to be tpm_key */ TPM_RESULT TPM_CertifyInfo_Set(TPM_CERTIFY_INFO *tpm_certify_info, TPM_KEY *tpm_key) { TPM_RESULT rc = 0; printf(" TPM_CertifyInfo_Set:\n"); if (rc == 0) { tpm_certify_info->keyUsage = tpm_key->keyUsage; tpm_certify_info->keyFlags = tpm_key->keyFlags; tpm_certify_info->authDataUsage = tpm_key->authDataUsage; rc = TPM_KeyParms_Copy(&(tpm_certify_info->algorithmParms), &(tpm_key->algorithmParms)); } /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY representation of the key to be certified */ if (rc == 0) { rc = TPM_SHA1(tpm_certify_info->pubkeyDigest, tpm_key->pubKey.size, tpm_key->pubKey.buffer, 0, NULL); } return rc; } /* TPM_CERTIFY_INFO2 */ /* TPM_CertifyInfo2_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_CertifyInfo2_Init(TPM_CERTIFY_INFO2 *tpm_certify_info2) { printf(" TPM_CertifyInfo2_Init:\n"); tpm_certify_info2->fill = 0x00; tpm_certify_info2->payloadType = TPM_PT_ASYM; tpm_certify_info2->keyUsage = TPM_KEY_UNINITIALIZED; tpm_certify_info2->keyFlags = 0; tpm_certify_info2->authDataUsage = TPM_AUTH_ALWAYS; TPM_KeyParms_Init(&(tpm_certify_info2->algorithmParms)); TPM_Digest_Init(tpm_certify_info2->pubkeyDigest); TPM_Nonce_Init(tpm_certify_info2->data); tpm_certify_info2->parentPCRStatus = TRUE; TPM_SizedBuffer_Init(&(tpm_certify_info2->pcrInfo)); TPM_SizedBuffer_Init(&(tpm_certify_info2->migrationAuthority)); tpm_certify_info2->tpm_pcr_info_short = NULL; return; } #if 0 /* TPM_CertifyInfo2_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_CertifyInfo2_Init() After use, call TPM_CertifyInfo2_Delete() to free memory */ TPM_RESULT TPM_CertifyInfo2_Load(TPM_CERTIFY_INFO2 *tpm_certify_info2, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; printf(" TPM_CertifyInfo2_Load:\n"); /* check tag */ if (rc == 0) { rc = TPM_CheckTag(TPM_TAG_CERTIFY_INFO2, stream, stream_size); } /* load fill */ if (rc == 0) { rc = TPM_Load8(&(tpm_certify_info2->fill), stream, stream_size); } /* check fill immediately to ease debugging */ if (rc == 0) { if (tpm_certify_info2->fill != 0x00) { printf("TPM_CertifyInfo2_Load: Error checking fill %02x\n", tpm_certify_info2->fill); rc = TPM_INVALID_STRUCTURE; } } /* load payloadType */ if (rc == 0) { rc = TPM_Load8(&(tpm_certify_info2->payloadType), stream, stream_size); } /* load keyUsage */ if (rc == 0) { rc = TPM_Load16(&(tpm_certify_info2->keyUsage), stream, stream_size); } /* load keyFlags */ if (rc == 0) { rc = TPM_KeyFlags_Load(&(tpm_certify_info2->keyFlags), stream, stream_size); } /* load authDataUsage */ if (rc == 0) { rc = TPM_Load8(&(tpm_certify_info2->authDataUsage), stream, stream_size); } /* load algorithmParms */ if (rc == 0) { rc = TPM_KeyParms_Load(&(tpm_certify_info2->algorithmParms), stream, stream_size); } /* load pubkeyDigest */ if (rc == 0) { rc = TPM_Digest_Load(tpm_certify_info2->pubkeyDigest, stream, stream_size); } /* load data */ if (rc == 0) { rc = TPM_Nonce_Load(tpm_certify_info2->data, stream, stream_size); } /* load parentPCRStatus */ if (rc == 0) { rc = TPM_LoadBool(&(tpm_certify_info2->parentPCRStatus), stream, stream_size); } /* load pcrInfo */ if (rc == 0) { rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->pcrInfo), stream, stream_size); } /* set TPM_PCR_INFO2 tpm_pcr_info cache from pcrInfo */ if (rc == 0) { rc = TPM_PCRInfoShort_CreateFromBuffer(&(tpm_certify_info2->tpm_pcr_info_short), &(tpm_certify_info2->pcrInfo)); } /* load migrationAuthority */ if (rc == 0) { rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->migrationAuthority), stream, stream_size); } /* check migrationAuthority immediately to ease debugging */ if (rc == 0) { if ((tpm_certify_info2->migrationAuthority.buffer != NULL) && (tpm_certify_info2->migrationAuthority.size != TPM_DIGEST_SIZE)) { printf("TPM_CertifyInfo2_Load: Error checking migrationAuthority %p, %u\n", tpm_certify_info2->migrationAuthority.buffer, tpm_certify_info2->migrationAuthority.size); rc = TPM_INVALID_STRUCTURE; } } return rc; } #endif /* TPM_CertifyInfo2_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_CertifyInfo2_Store(TPM_STORE_BUFFER *sbuffer, TPM_CERTIFY_INFO2 *tpm_certify_info2) { TPM_RESULT rc = 0; printf(" TPM_CertifyInfo2_Store:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CERTIFY_INFO2); } /* store fill */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->fill), sizeof(BYTE)); } /* store payloadType */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->payloadType), sizeof(TPM_PAYLOAD_TYPE)); } /* store keyUsage */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info2->keyUsage); } /* store keyFlags */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info2->keyFlags); } /* store authDataUsage */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->authDataUsage), sizeof(TPM_AUTH_DATA_USAGE)); } /* store algorithmParms */ if (rc == 0) { rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info2->algorithmParms)); } /* store pubkeyDigest */ if (rc == 0) { rc = TPM_Digest_Store(sbuffer, tpm_certify_info2->pubkeyDigest); } /* store data */ if (rc == 0) { rc = TPM_Nonce_Store(sbuffer, tpm_certify_info2->data); } /* store parentPCRStatus */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->parentPCRStatus), sizeof(TPM_BOOL)); } /* copy cache to pcrInfo */ if (rc == 0) { rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info2->pcrInfo), tpm_certify_info2->tpm_pcr_info_short, (TPM_STORE_FUNCTION_T)TPM_PCRInfoShort_Store); } /* copy pcrInfo to sbuffer */ if (rc == 0) { rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->pcrInfo)); } /* store migrationAuthority */ if (rc == 0) { rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->migrationAuthority)); } return rc; } /* TPM_CertifyInfo2_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_CertifyInfo2_Init to set members back to default values The object itself is not freed */ void TPM_CertifyInfo2_Delete(TPM_CERTIFY_INFO2 *tpm_certify_info2) { printf(" TPM_CertifyInfo2_Delete:\n"); if (tpm_certify_info2 != NULL) { TPM_KeyParms_Delete(&(tpm_certify_info2->algorithmParms)); /* pcrInfo */ TPM_SizedBuffer_Delete(&(tpm_certify_info2->pcrInfo)); /* pcr cache */ TPM_PCRInfoShort_Delete(tpm_certify_info2->tpm_pcr_info_short); free(tpm_certify_info2->tpm_pcr_info_short); TPM_SizedBuffer_Delete(&(tpm_certify_info2->migrationAuthority)); TPM_CertifyInfo2_Init(tpm_certify_info2); } return; } /* TPM_CertifyInfo2_Set() fills in tpm_certify_info2 with the information from the key pointed to by tpm_key. */ TPM_RESULT TPM_CertifyInfo2_Set(TPM_CERTIFY_INFO2 *tpm_certify_info2, TPM_KEY *tpm_key) { TPM_RESULT rc = 0; TPM_STORE_ASYMKEY *tpm_store_asymkey; printf(" TPM_CertifyInfo_Set:\n"); /* get the TPM_STORE_ASYMKEY object */ if (rc == 0) { rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); } if (rc == 0) { tpm_certify_info2->payloadType = tpm_store_asymkey->payload; tpm_certify_info2->keyUsage = tpm_key->keyUsage; tpm_certify_info2->keyFlags = tpm_key->keyFlags; tpm_certify_info2->authDataUsage = tpm_key->authDataUsage; rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); } if (rc == 0) { rc = TPM_KeyParms_Copy(&(tpm_certify_info2->algorithmParms), &(tpm_key->algorithmParms)); } /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY representation of the key to be certified */ if (rc == 0) { rc = TPM_SHA1(tpm_certify_info2->pubkeyDigest, tpm_key->pubKey.size, tpm_key->pubKey.buffer, 0, NULL); } return rc; } /* TPM_SYMMETRIC_KEY */ /* TPM_SymmetricKey_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_SymmetricKey_Init(TPM_SYMMETRIC_KEY *tpm_symmetric_key) { printf(" TPM_SymmetricKey_Init:\n"); tpm_symmetric_key->algId = 0; tpm_symmetric_key->encScheme = TPM_ES_NONE; tpm_symmetric_key->size = 0; tpm_symmetric_key->data = NULL; return; } /* TPM_SymmetricKey_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_SymmetricKey_Init() After use, call TPM_SymmetricKey_Delete() to free memory */ TPM_RESULT TPM_SymmetricKey_Load(TPM_SYMMETRIC_KEY *tpm_symmetric_key, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; printf(" TPM_SymmetricKey_Load:\n"); /* load algId */ if (rc == 0) { rc = TPM_Load32(&(tpm_symmetric_key->algId), stream, stream_size); } /* load encScheme */ if (rc == 0) { rc = TPM_Load16(&(tpm_symmetric_key->encScheme), stream, stream_size); } /* load size */ if (rc == 0) { rc = TPM_Load16(&(tpm_symmetric_key->size), stream, stream_size); } /* allocate memory for the data */ if ((rc == 0) && (tpm_symmetric_key->size > 0)) { rc = TPM_Malloc(&(tpm_symmetric_key->data), tpm_symmetric_key->size); } /* load data */ if ((rc == 0) && (tpm_symmetric_key->size > 0)) { rc = TPM_Loadn(tpm_symmetric_key->data, tpm_symmetric_key->size, stream, stream_size); } return rc; } /* TPM_SymmetricKey_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_SymmetricKey_Store(TPM_STORE_BUFFER *sbuffer, const TPM_SYMMETRIC_KEY *tpm_symmetric_key) { TPM_RESULT rc = 0; printf(" TPM_SymmetricKey_Store:\n"); /* store algId */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_symmetric_key->algId); } /* store encScheme */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->encScheme); } /* NOTE: Cannot use TPM_SizedBuffer_Store since the first parameter is a uint16_t */ /* store size */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->size); } /* store data */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key->data, tpm_symmetric_key->size); } return rc; } /* TPM_SymmetricKey_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_SymmetricKey_Init to set members back to default values The object itself is not freed */ void TPM_SymmetricKey_Delete(TPM_SYMMETRIC_KEY *tpm_symmetric_key) { printf(" TPM_SymmetricKey_Delete:\n"); if (tpm_symmetric_key != NULL) { free(tpm_symmetric_key->data); TPM_SymmetricKey_Init(tpm_symmetric_key); } return; } /* TPM_SymmetricKeyData_EncryptSbuffer() encrypts 'sbuffer' to 'encrypt_data' Padding is included, so the output may be larger than the input. 'encrypt_data' must be free by the caller */ TPM_RESULT TPM_SymmetricKeyData_EncryptSbuffer(TPM_SIZED_BUFFER *encrypt_data, TPM_STORE_BUFFER *sbuffer, const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data) { TPM_RESULT rc = 0; const unsigned char *decrypt_data; /* serialization buffer */ uint32_t decrypt_data_size; /* serialization size */ printf(" TPM_SymmetricKeyData_EncryptSbuffer:\n"); if (rc == 0) { /* get the serialization results */ TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); /* platform dependent symmetric key encrypt */ rc = TPM_SymmetricKeyData_Encrypt(&(encrypt_data->buffer), /* output, caller frees */ &(encrypt_data->size), /* output */ decrypt_data, /* input */ decrypt_data_size, /* input */ tpm_symmetric_key_data); } return rc; } /* TPM_SymmetricKeyData_StreamCrypt() encrypts or decrypts 'data_in' to 'data_out ' It assumes that the size of data_out and data_in are equal, and that a stream cipher mode is used. For the supported stream ciphers, encrypt and decrypt are equivalent, so no direction flag is required. AES 128 with CTR or OFB modes are supported. For CTR mode, pad is the initial count. For OFB mode, pad is the IV. */ TPM_RESULT TPM_SymmetricKeyData_StreamCrypt(unsigned char *data_out, /* output */ const unsigned char *data_in, /* input */ uint32_t data_size, /* input */ TPM_ALGORITHM_ID algId, /* algorithm */ TPM_ENC_SCHEME encScheme, /* mode */ const unsigned char *symmetric_key, /* input */ uint32_t symmetric_key_size, /* input */ unsigned char *pad_in, /* input */ uint32_t pad_in_size) /* input */ { TPM_RESULT rc = 0; printf(" TPM_SymmetricKeyData_StreamCrypt:\n"); switch (algId) { case TPM_ALG_AES128: switch (encScheme) { case TPM_ES_SYM_CTR: rc = TPM_SymmetricKeyData_CtrCrypt(data_out, data_in, data_size, symmetric_key, symmetric_key_size, pad_in, pad_in_size); break; case TPM_ES_SYM_OFB: rc = TPM_SymmetricKeyData_OfbCrypt(data_out, data_in, data_size, symmetric_key, symmetric_key_size, pad_in, pad_in_size); break; default: printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad AES128 encScheme %04x\n", encScheme); rc = TPM_INAPPROPRIATE_ENC; break; } break; default: printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad algID %08x\n", algId); rc = TPM_INAPPROPRIATE_ENC; break; } return rc; } /* These functions perform high-level, platform independent functions. They call the lower level, platform dependent crypto functions in tpm_crypto.c */ /* TPM_SHA1Sbuffer() calculates the SHA-1 digest of a TPM_STORE_BUFFER. This is commonly used when calculating a digest on a serialized structure. Structures are serialized to a TPM_STORE_BUFFER. The TPM_STORE_BUFFER is not deleted. */ TPM_RESULT TPM_SHA1Sbuffer(TPM_DIGEST tpm_digest, TPM_STORE_BUFFER *sbuffer) { TPM_RESULT rc = 0; const unsigned char *buffer; /* serialized buffer */ uint32_t length; /* serialization length */ printf(" TPM_SHA1Sbuffer:\n"); if (rc == 0) { /* get the components of the TPM_STORE_BUFFER */ TPM_Sbuffer_Get(sbuffer, &buffer, &length); TPM_PrintFour(" TPM_SHA1Sbuffer: input", buffer); /* hash the serialized buffer to tpm_digest */ rc = TPM_SHA1(tpm_digest, length, buffer, 0, NULL); } return rc; } /* TPM_SHA1_GenerateStructure() generates a SHA-1 digest of a structure. It serializes the structure and hashes the result. tpmStructure is the structure to be serialized storeFunction is the serialization function for the structure */ TPM_RESULT TPM_SHA1_GenerateStructure(TPM_DIGEST tpm_digest, void *tpmStructure, TPM_STORE_FUNCTION_T storeFunction) { TPM_RESULT rc = 0; TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ printf(" TPM_SHA1_GenerateStructure:\n"); TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ /* Serialize the structure */ if (rc == 0) { rc = storeFunction(&sbuffer, tpmStructure); } /* hash the serialized buffer to tpm_hmac */ if (rc == 0) { rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); } TPM_Sbuffer_Delete(&sbuffer); /* @1 */ return rc; } /* TPM_SHA1_CheckStructure() generates a SHA-1 digest of a structure. It serializes the structure and hashes the result. It compares the result to 'expected_digest' and returns 'error' on mismatch. tpmStructure is the structure to be serialized storeFunction is the serialization function for the structure */ TPM_RESULT TPM_SHA1_CheckStructure(TPM_DIGEST expected_digest, void *tpmStructure, TPM_STORE_FUNCTION_T storeFunction, TPM_RESULT error) { TPM_RESULT rc = 0; TPM_DIGEST actual_digest; printf(" TPM_SHA1_CheckStructure:\n"); /* hash the serialized buffer to tpm_digest */ if (rc == 0) { rc = TPM_SHA1_GenerateStructure(actual_digest, tpmStructure, storeFunction); } /* check the digests */ if (rc == 0) { rc = TPM_Digest_Compare(actual_digest, expected_digest); if (rc != 0) { rc = error; } } return rc; } /* TPM_SHA1() can be called directly to hash a list of streams. The ... arguments to be hashed are a list of the form size_t length, unsigned char *buffer terminated by a 0 length */ TPM_RESULT TPM_SHA1(TPM_DIGEST md, ...) { TPM_RESULT rc = 0; va_list ap; printf(" TPM_SHA1:\n"); va_start(ap, md); rc = TPM_SHA1_valist(md, 0, NULL, ap); va_end(ap); return rc; } /* TPM_SHA1_Check() digests the list of streams and compares the result to 'digest_expect' */ TPM_RESULT TPM_SHA1_Check(TPM_DIGEST digest_expect, ...) { TPM_RESULT rc = 0; TPM_DIGEST digest_actual; va_list ap; printf(" TPM_SHA1_Check:\n"); if (rc == 0) { va_start(ap, digest_expect); rc = TPM_SHA1_valist(digest_actual, 0, NULL, ap); va_end(ap); } if (rc == 0) { rc = TPM_Digest_Compare(digest_expect, digest_actual); } return rc; } /* TPM_SHA1_valist() is the internal function, called with the va_list already created. It is called from TPM_SHA1() to do a simple hash. Typically length0==0 and buffer0==NULL. It can also be called from the HMAC function to hash the variable number of input parameters. In that case, the va_list for the text is already formed. length0 and buffer0 are used to input the padded key. */ static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, uint32_t length0, unsigned char *buffer0, va_list ap) { TPM_RESULT rc = 0; uint32_t length; unsigned char *buffer; void *context = NULL; /* platform dependent context */ TPM_BOOL done = FALSE; printf(" TPM_SHA1_valist:\n"); if (rc == 0) { rc = TPM_SHA1InitCmd(&context); } if (rc == 0) { if (length0 !=0) { /* optional first text block */ printf(" TPM_SHA1_valist: Digesting %u bytes\n", length0); rc = TPM_SHA1UpdateCmd(context, buffer0, length0); /* hash the buffer */ } } while ((rc == 0) && !done) { length = va_arg(ap, uint32_t); /* first vararg is the length */ if (length != 0) { /* loop until a zero length argument terminates */ buffer = va_arg(ap, unsigned char *); /* second vararg is the array */ printf(" TPM_SHA1_valist: Digesting %u bytes\n", length); rc = TPM_SHA1UpdateCmd(context, buffer, length); /* hash the buffer */ } else { done = TRUE; } } if (rc == 0) { rc = TPM_SHA1FinalCmd(md, context); } if (rc == 0) { TPM_PrintFour(" TPM_SHA1_valist: Digest", md); } /* call TPM_SHA1Delete even if there was an error */ TPM_SHA1Delete(&context); return rc; } /* TPM_HMAC_GenerateSbuffer() calculates the HMAC digest of a TPM_STORE_BUFFER. This is commonly used when calculating an HMAC on a serialized structure. Structures are serialized to a TPM_STORE_BUFFER. The TPM_STORE_BUFFER is not deleted. */ TPM_RESULT TPM_HMAC_GenerateSbuffer(TPM_HMAC tpm_hmac, const TPM_SECRET hmac_key, TPM_STORE_BUFFER *sbuffer) { TPM_RESULT rc = 0; const unsigned char *buffer; /* serialized buffer */ uint32_t length; /* serialization length */ printf(" TPM_HMAC_GenerateSbuffer:\n"); if (rc == 0) { /* get the components of the TPM_STORE_BUFFER */ TPM_Sbuffer_Get(sbuffer, &buffer, &length); /* HMAC the serialized buffer to tpm_hmac */ rc = TPM_HMAC_Generate(tpm_hmac, hmac_key, length, buffer, 0, NULL); } return rc; } /* TPM_HMAC_GenerateStructure() generates an HMAC of a structure. It serializes the structure and HMAC's the result. hmacKey is the HMAC key tpmStructure is the structure to be serialized storeFunction is the serialization function for the structure */ TPM_RESULT TPM_HMAC_GenerateStructure(TPM_HMAC tpm_hmac, const TPM_SECRET hmac_key, void *tpmStructure, TPM_STORE_FUNCTION_T storeFunction) { TPM_RESULT rc = 0; TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ printf(" TPM_HMAC_GenerateStructure:\n"); TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ /* Serialize the structure */ if (rc == 0) { rc = storeFunction(&sbuffer, tpmStructure); } /* hash the serialized buffer to tpm_hmac */ if (rc == 0) { rc = TPM_HMAC_GenerateSbuffer(tpm_hmac, hmac_key, &sbuffer); } TPM_Sbuffer_Delete(&sbuffer); /* @1 */ return rc; } /* TPM_HMAC_Generate() can be called directly to HMAC a list of streams. The ... arguments are a message list of the form size_t length, unsigned char *buffer terminated by a 0 length */ TPM_RESULT TPM_HMAC_Generate(TPM_HMAC tpm_hmac, const TPM_SECRET hmac_key, ...) { TPM_RESULT rc = 0; va_list ap; printf(" TPM_HMAC_Generate:\n"); va_start(ap, hmac_key); rc = TPM_HMAC_Generatevalist(tpm_hmac, hmac_key, ap); va_end(ap); return rc; } /* TPM_HMAC_Generatevalist() is the internal function, called with the va_list already created. It is called from TPM_HMAC_Generate() and TPM_HMAC_Check() with the va_list for the text already formed. */ #define TPM_HMAC_BLOCK_SIZE 64 static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC tpm_hmac, const TPM_SECRET key, va_list ap) { TPM_RESULT rc = 0; unsigned char ipad[TPM_HMAC_BLOCK_SIZE]; unsigned char opad[TPM_HMAC_BLOCK_SIZE]; size_t i; TPM_DIGEST inner_hash; printf(" TPM_HMAC_Generatevalist:\n"); /* calculate key XOR ipad and key XOR opad */ if (rc == 0) { /* first part, key XOR pad */ for (i = 0 ; i < TPM_AUTHDATA_SIZE ; i++) { ipad[i] = key[i] ^ 0x36; /* magic numbers from RFC 2104 */ opad[i] = key[i] ^ 0x5c; } /* second part, 0x00 XOR pad */ memset(ipad + TPM_AUTHDATA_SIZE, 0x36, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); memset(opad + TPM_AUTHDATA_SIZE, 0x5c, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); /* calculate the inner hash, hash the key XOR ipad and the text */ rc = TPM_SHA1_valist(inner_hash, TPM_HMAC_BLOCK_SIZE, ipad, ap); } /* hash the key XOR opad and the previous hash */ if (rc == 0) { rc = TPM_SHA1(tpm_hmac, TPM_HMAC_BLOCK_SIZE, opad, TPM_DIGEST_SIZE, inner_hash, 0, NULL); } if (rc == 0) { TPM_PrintFour(" TPM_HMAC_Generatevalist: HMAC", tpm_hmac); } return rc; } /* TPM_HMAC_CheckSbuffer() checks the HMAC of a TPM_STORE_BUFFER. This is commonly used when checking an HMAC on a serialized structure. Structures are serialized to a TPM_STORE_BUFFER. The TPM_STORE_BUFFER is not deleted. */ TPM_RESULT TPM_HMAC_CheckSbuffer(TPM_BOOL *valid, /* result */ TPM_HMAC expect, /* expected */ const TPM_SECRET hmac_key, /* key */ TPM_STORE_BUFFER *sbuffer) /* data stream */ { TPM_RESULT rc = 0; const unsigned char *buffer; /* serialized buffer */ uint32_t length; /* serialization length */ printf(" TPM_HMAC_CheckSbuffer:\n"); if (rc == 0) { /* get the components of the TPM_STORE_BUFFER */ TPM_Sbuffer_Get(sbuffer, &buffer, &length); /* HMAC the serialized buffer to tpm_hmac */ rc = TPM_HMAC_Check(valid, expect, hmac_key, length, buffer, 0, NULL); } return rc; } /* TPM_HMAC_Check() can be called directly to check the HMAC of a list of streams. The ... arguments are a list of the form size_t length, unsigned char *buffer terminated by a 0 length */ TPM_RESULT TPM_HMAC_Check(TPM_BOOL *valid, TPM_HMAC expect, const TPM_SECRET key, ...) { TPM_RESULT rc = 0; va_list ap; TPM_HMAC actual; int result; printf(" TPM_HMAC_Check:\n"); va_start(ap, key); if (rc == 0) { rc = TPM_HMAC_Generatevalist(actual, key, ap); } if (rc == 0) { TPM_PrintFour(" TPM_HMAC_Check: Calculated", actual); TPM_PrintFour(" TPM_HMAC_Check: Received ", expect); result = memcmp(expect, actual, TPM_DIGEST_SIZE); if (result == 0) { *valid = TRUE; } else { *valid = FALSE; } } va_end(ap); return rc; } /* TPM_HMAC_CheckStructure() is a generic function that checks the integrity HMAC of a structure. hmacKey is the HMAC key tpmStructure is the structure to be serialized expect is the expected HMAC, a member of the structure storeFunction is the serialization function for the structure error is the failure return code The function saves a copy of the expected HMAC, and then NULL's the structure member. It serializes the structure, generates an HMAC, and compares it to the expected value. As a side effect, the structure member is zeroed. */ TPM_RESULT TPM_HMAC_CheckStructure(const TPM_SECRET hmac_key, void *tpmStructure, TPM_HMAC expect, TPM_STORE_FUNCTION_T storeFunction, TPM_RESULT error) { TPM_RESULT rc = 0; TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ TPM_HMAC saveExpect; TPM_BOOL valid; printf(" TPM_HMAC_CheckStructure:\n"); TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ if (rc == 0) { TPM_Digest_Copy(saveExpect, expect); /* save the expected value */ TPM_Digest_Init(expect); /* set value in structure to NULL */ rc = storeFunction(&sbuffer, tpmStructure); } /* verify the HMAC of the serialized structure */ if (rc == 0) { rc = TPM_HMAC_CheckSbuffer(&valid, /* result */ saveExpect, /* expected */ hmac_key, /* key */ &sbuffer); /* data stream */ } if (rc == 0) { if (!valid) { printf("TPM_HMAC_CheckStructure: Error checking HMAC\n"); rc = error; } } TPM_Sbuffer_Delete(&sbuffer); /* @1 */ return rc; } /* TPM_XOR XOR's 'in1' and 'in2' of 'length', putting the result in 'out' */ void TPM_XOR(unsigned char *out, const unsigned char *in1, const unsigned char *in2, size_t length) { size_t i; for (i = 0 ; i < length ; i++) { out[i] = in1[i] ^ in2[i]; } return; } /* TPM_MGF1() generates an MGF1 'array' of length 'arrayLen' from 'seed' of length 'seedlen' The openSSL DLL doesn't export MGF1 in Windows or Linux 1.0.0, so this version is created from scratch. Algorithm and comments (not the code) from: PKCS #1: RSA Cryptography Specifications Version 2.1 B.2.1 MGF1 Prototype designed to be compatible with openSSL MGF1 is a Mask Generation Function based on a hash function. MGF1 (mgfSeed, maskLen) Options: Hash hash function (hLen denotes the length in octets of the hash function output) Input: mgfSeed seed from which mask is generated, an octet string maskLen intended length in octets of the mask, at most 2^32(hLen) Output: mask mask, an octet string of length l; or "mask too long" Error: "mask too long' */ TPM_RESULT TPM_MGF1(unsigned char *mask, uint32_t maskLen, const unsigned char *mgfSeed, uint32_t mgfSeedlen) { TPM_RESULT rc = 0; unsigned char counter[4]; /* 4 octets */ uint32_t count; /* counter as an integral type */ uint32_t outLen; TPM_DIGEST lastDigest; printf(" TPM_MGF1: Output length %u\n", maskLen); if (rc == 0) { /* this is possible with arrayLen on a 64 bit architecture, comment to quiet beam */ if ((maskLen / TPM_DIGEST_SIZE) > 0xffffffff) { /*constant condition*/ printf(" TPM_MGF1: Error (fatal), Output length too large for 32 bit counter\n"); rc = TPM_FAIL; /* should never occur */ } } /* 1.If l > 2^32(hLen), output "mask too long" and stop. */ /* NOTE Checked by caller */ /* 2. Let T be the empty octet string. */ /* 3. For counter from 0 to [masklen/hLen] - 1, do the following: */ for (count = 0, outLen = 0 ; (rc == 0) && (outLen < maskLen) ; count++) { /* a. Convert counter to an octet string C of length 4 octets - see Section 4.1 */ /* C = I2OSP(counter, 4) NOTE Basically big endian */ uint32_t count_n = htonl(count); memcpy(counter, &count_n, 4); /* b.Concatenate the hash of the seed mgfSeed and C to the octet string T: */ /* T = T || Hash (mgfSeed || C) */ /* If the entire digest is needed for the mask */ if ((outLen + TPM_DIGEST_SIZE) < maskLen) { rc = TPM_SHA1(mask + outLen, mgfSeedlen, mgfSeed, 4, counter, 0, NULL); outLen += TPM_DIGEST_SIZE; } /* if the mask is not modulo TPM_DIGEST_SIZE, only part of the final digest is needed */ else { /* hash to a temporary digest variable */ rc = TPM_SHA1(lastDigest, mgfSeedlen, mgfSeed, 4, counter, 0, NULL); /* copy what's needed */ memcpy(mask + outLen, lastDigest, maskLen - outLen); outLen = maskLen; /* outLen = outLen + maskLen - outLen */ } } /* 4.Output the leading l octets of T as the octet string mask. */ return rc; } /* TPM_MGF1_GenerateArray() generates an array of length arrayLen using the varargs as the seed. Since the seed is a known length, it is passed in rather that extracted from the varargs. If the seed length turns out to be wrong once the varargs are parsed, TPM_FAIL is returned. 'array' must be freed by the caller. */ TPM_RESULT TPM_MGF1_GenerateArray(unsigned char **array, uint32_t arrayLen, uint32_t seedLen, ...) { TPM_RESULT rc = 0; va_list ap; unsigned char *seed; /* constructed MGF1 seed */ size_t vaLength; /* next seed segment length */ unsigned char *vaBuffer; /* next seed segment buffer */ uint32_t seedLeft; /* remaining seed bytes required */ unsigned char *seedBuffer; /* running pointer to the seed array */ TPM_BOOL done = FALSE; /* done when a vaLength == 0 is reached */ printf(" TPM_MGF1_GenerateArray: arrayLen %u seedLen %u\n", arrayLen, seedLen); seed = NULL; /* freed @1 */ *array = NULL; /* freed by caller */ va_start(ap, seedLen); /* allocate temporary memory for the seed */ if (rc == 0) { rc = TPM_Malloc(&seed, seedLen); seedBuffer = seed; seedLeft = seedLen; } /* construct the seed */ while ((rc == 0) && !done) { vaLength = (size_t)va_arg(ap, uint32_t); /* first vararg is the length */ if (vaLength != 0) { /* loop until a zero length argument terminates */ if (rc == 0) { printf(" TPM_MGF1_GenerateArray: Appending %lu bytes\n", (unsigned long)vaLength); if (vaLength > seedLeft) { printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too small\n"); rc = TPM_FAIL; /* internal error, should never occur */ } } if (rc == 0) { vaBuffer = va_arg(ap, unsigned char *); /* second vararg is the array */ memcpy(seedBuffer, vaBuffer, vaLength); seedBuffer += vaLength; seedLeft-= vaLength; } } else { done = TRUE; if (seedLeft != 0) { printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too large by %u\n", seedLeft); rc = TPM_FAIL; /* internal error, should never occur */ } } } /* allocate memory for the array */ if (rc == 0) { rc = TPM_Malloc(array, arrayLen); } /* generate the MGF1 array */ if (rc == 0) { TPM_MGF1(*array, arrayLen, seed, seedLen); TPM_PrintFour(" TPM_MGF1_GenerateArray: MGF1", *array); } va_end(ap); free(seed); /* @1 */ return rc; } /* TPM_bn2binMalloc() allocates a buffer 'bin' and loads it from 'bn'. 'bytes' is set to the allocated size of 'bin'. If padBytes is non-zero, 'bin' is padded with leading zeros if necessary, so that 'bytes' will equal 'padBytes'. This is used when TPM data structures expect a fixed length while the crypto library 'bn to bin' function might truncates leading zeros. '*bin' must be freed by the caller */ TPM_RESULT TPM_bn2binMalloc(unsigned char **bin, /* freed by caller */ unsigned int *bytes, TPM_BIGNUM bn, uint32_t padBytes) { TPM_RESULT rc = 0; printf(" TPM_bn2binMalloc: padBytes %u\n", padBytes); /* number of bytes required in the bin array */ if (rc == 0) { rc = TPM_BN_num_bytes(bytes, bn); } /* calculate the array size to malloc */ if (rc == 0) { /* padBytes 0 says that no padding is required */ if (padBytes == 0) { padBytes = *bytes; /* setting equal yields no padding */ } /* if the array with padding is still less than the number of bytes required by the bignum, this function fails */ if (padBytes < *bytes) { printf("TPM_bn2binMalloc: Error, " "padBytes %u less than BN bytes %u\n", padBytes, *bytes); rc = TPM_SIZE; } /* log if padding is occurring */ if (padBytes != *bytes) { printf(" TPM_bn2binMalloc: padBytes %u bytes %u\n", padBytes, *bytes); } } /* allocate for the padded array */ if (rc == 0) { rc = TPM_Malloc(bin, padBytes); *bytes = padBytes; } /* call the bignum to bin conversion */ if (rc == 0) { rc = TPM_bn2binArray(*bin, padBytes, bn); } return rc; } /* TPM_bn2binArray() loads the array 'bin' of size 'bytes' from 'bn' The data from 'bn' is right justified and zero padded. */ TPM_RESULT TPM_bn2binArray(unsigned char *bin, unsigned int bytes, TPM_BIGNUM bn) { TPM_RESULT rc = 0; unsigned int numBytes; printf(" TPM_bn2binArray: size %u\n", bytes); if (rc == 0) { /* zero pad */ memset(bin, 0, bytes); /* bytes required for the bignum */ rc = TPM_BN_num_bytes(&numBytes, bn); } /* if the array is less than the number of bytes required by the bignum, this function fails */ if (rc == 0) { printf(" TPM_bn2binArray: numBytes in bignum %u\n", numBytes); if (numBytes > bytes) { printf("TPM_bn2binArray: Error, " "BN bytes %u greater than array bytes %u\n", numBytes, bytes); rc = TPM_SIZE; } } if (rc == 0) { /* if there are bytes in the bignum (it is not zero) */ if (numBytes > 0) { rc = TPM_bn2bin(bin + bytes - numBytes, /* store right justified */ bn); } } return rc; } /* TPM_2bin2bn() converts two byte arrays to a positive BIGNUM. The two byte arrays are concatenated. The concatenation is used to create the BIGNUM. bignum must be freed by the caller. */ TPM_RESULT TPM_2bin2bn(TPM_BIGNUM *bignum_in, /* freed by caller */ const unsigned char *bin0, uint32_t size0, const unsigned char *bin1, uint32_t size1) { TPM_RESULT rc = 0; /* TPM return code */ TPM_STORE_BUFFER sBuffer; /* used of >1 element or first element is negative */ const unsigned char *buffer; uint32_t size; printf(" TPM_bin2bn:\n"); TPM_Sbuffer_Init(&sBuffer); /* freed @1 */ /* append the first element */ if (rc == 0) { rc = TPM_Sbuffer_Append(&sBuffer, bin0, size0); } /* append the next element */ if (rc == 0) { rc = TPM_Sbuffer_Append(&sBuffer, bin1, size1); } /* create the BIGNUM from the array */ if (rc == 0) { TPM_Sbuffer_Get(&sBuffer, &buffer, &size); /* create the BIGNUM */ rc = TPM_bin2bn(bignum_in, buffer, size); /* freed by caller */ } TPM_Sbuffer_Delete(&sBuffer); /* @1 */ return rc; } /* TPM_RSAPrivateDecryptMalloc() allocates a buffer 'decrypt_data' of size 'decrypt_data_size' and then calls TPM_RSAPrivateDecryptH(). */ TPM_RESULT TPM_RSAPrivateDecryptMalloc(unsigned char **decrypt_data, /* decrypted data */ uint32_t *decrypt_data_length, /* length of data put into decrypt_data */ unsigned char *encrypt_data, uint32_t encrypt_data_size, TPM_KEY *tpm_key) { TPM_RESULT rc = 0; /* allocate space for the decrypted blob */ printf(" TPM_RSAPrivateDecryptMalloc: Return max data size %u bytes\n", tpm_key->pubKey.size); if (rc == 0) { rc = TPM_Malloc(decrypt_data, tpm_key->pubKey.size); } if (rc == 0) { rc = TPM_RSAPrivateDecryptH(*decrypt_data, decrypt_data_length, tpm_key->pubKey.size, encrypt_data, encrypt_data_size, tpm_key); } return rc; } /* TPM_RSAPrivateDecryptH() decrypts 'encrypt_data' using the private key in 'tpm_key' and 'decrypt_data_length' bytes are moved to 'decrypt_data'. 'decrypt_data_length' is at most 'decrypt_data_size'. */ TPM_RESULT TPM_RSAPrivateDecryptH(unsigned char *decrypt_data, /* decrypted data */ uint32_t *decrypt_data_length, /* length of data put into decrypt_data */ uint32_t decrypt_data_size, /* size of decrypt_data buffer */ unsigned char *encrypt_data, uint32_t encrypt_data_size, TPM_KEY *tpm_key) { TPM_RESULT rc = 0; unsigned char *narr; /* public modulus */ uint32_t nbytes; unsigned char *earr; /* public exponent */ uint32_t ebytes; unsigned char *darr; /* private exponent */ uint32_t dbytes; printf(" TPM_RSAPrivateDecryptH: Data size %u bytes\n", encrypt_data_size); TPM_PrintFourLimit(" TPM_RSAPrivateDecryptH: Encrypt data", encrypt_data, encrypt_data_size); if (rc == 0) { if (tpm_key == NULL) { printf("TPM_RSAPrivateDecryptH: Error, NULL key\n"); rc = TPM_DECRYPT_ERROR; } } /* extract the public key from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); } /* extract the private key from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); } /* extract the exponent from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); } /* check the key size vs the data size */ if (rc == 0) { if (encrypt_data_size > nbytes) { printf("TPM_RSAPrivateDecryptH: Error, data size too long for key size %u bytes\n", nbytes); rc = TPM_BAD_DATASIZE; } } if (rc == 0) { /* debug printing */ printf(" TPM_RSAPrivateDecryptH: Public key length %u\n", nbytes); printf(" TPM_RSAPrivateDecryptH: Private key length %u\n", dbytes); TPM_PrintFour(" TPM_RSAPrivateDecryptH: Public key", narr); printf(" TPM_RSAPrivateDecryptH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); TPM_PrintFour(" TPM_RSAPrivateDecryptH: Private key", darr); /* decrypt with private key */ rc = TPM_RSAPrivateDecrypt(decrypt_data, /* decrypted data */ decrypt_data_length, /* length of data put into decrypt_data */ decrypt_data_size, /* size of decrypt_data buffer */ tpm_key->algorithmParms.encScheme, /* encryption scheme */ encrypt_data, /* encrypted data */ encrypt_data_size, narr, /* public modulus */ nbytes, earr, /* public exponent */ ebytes, darr, /* private exponent */ dbytes); } if (rc == 0) { TPM_PrintFourLimit(" TPM_RSAPrivateDecryptH: Decrypt data", decrypt_data, *decrypt_data_length); } return rc; } /* TPM_RSAPublicEncryptSbuffer_Key() encrypts 'sbuffer' using the public key in 'tpm_key' and puts the results in 'encData' */ TPM_RESULT TPM_RSAPublicEncryptSbuffer_Key(TPM_SIZED_BUFFER *enc_data, TPM_STORE_BUFFER *sbuffer, TPM_KEY *tpm_key) { TPM_RESULT rc = 0; const unsigned char *decrypt_data; /* serialization buffer */ uint32_t decrypt_data_size; /* serialization size */ printf(" TPM_RSAPublicEncryptSbuffer_Key:\n"); /* get the serialization results */ TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); /* encrypt the serialization buffer with the public key, and place the result in the enc_data buffer */ rc = TPM_RSAPublicEncrypt_Key(enc_data, decrypt_data, decrypt_data_size, tpm_key); return rc; } /* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_key' and puts the results in 'encData' */ TPM_RESULT TPM_RSAPublicEncrypt_Key(TPM_SIZED_BUFFER *enc_data, const unsigned char *decrypt_data, size_t decrypt_data_size, TPM_KEY *tpm_key) { TPM_RESULT rc = 0; unsigned char *narr; /* public modulus */ uint32_t nbytes; unsigned char *earr; /* public exponent */ uint32_t ebytes; printf(" TPM_RSAPublicEncrypt_Key: Data size %lu bytes\n", (unsigned long)decrypt_data_size); if (rc == 0) { if (tpm_key == NULL) { printf("TPM_RSAPublicEncrypt_Key: Error, NULL key\n"); rc = TPM_ENCRYPT_ERROR; } } /* extract the public key from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); } /* extract the exponent from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); } if (rc == 0) { rc = TPM_RSAPublicEncrypt_Common(enc_data, decrypt_data, decrypt_data_size, tpm_key->algorithmParms.encScheme, /* encryption scheme */ narr, nbytes, earr, ebytes); } return rc; } /* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_pubkey' and puts the results in 'encData' */ TPM_RESULT TPM_RSAPublicEncrypt_Pubkey(TPM_SIZED_BUFFER *enc_data, const unsigned char *decrypt_data, size_t decrypt_data_size, TPM_PUBKEY *tpm_pubkey) { TPM_RESULT rc = 0; unsigned char *narr; /* public modulus */ uint32_t nbytes; unsigned char *earr; /* public exponent */ uint32_t ebytes; printf(" TPM_RSAPublicEncrypt_Pubkey: Data size %lu bytes\n", (unsigned long)decrypt_data_size); if (rc == 0) { if (tpm_pubkey == NULL) { printf("TPM_RSAPublicEncrypt_Pubkey: Error, NULL key\n"); rc = TPM_ENCRYPT_ERROR; } } /* extract the public key from TPM_PUBKEY */ if (rc == 0) { rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); } /* extract the exponent from TPM_KEY */ if (rc == 0) { rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); } if (rc == 0) { rc = TPM_RSAPublicEncrypt_Common(enc_data, decrypt_data, decrypt_data_size, tpm_pubkey->algorithmParms.encScheme, narr, nbytes, earr, ebytes); } return rc; } /* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key modulus and exponent, and puts the results in 'encData' */ TPM_RESULT TPM_RSAPublicEncrypt_Common(TPM_SIZED_BUFFER *enc_data, const unsigned char *decrypt_data, size_t decrypt_data_size, TPM_ENC_SCHEME encScheme, unsigned char *narr, /* public modulus */ uint32_t nbytes, unsigned char *earr, /* public exponent */ uint32_t ebytes) { TPM_RESULT rc = 0; unsigned char *encrypt_data = NULL; printf(" TPM_RSAPublicEncrypt_Common: Data size %lu bytes\n", (unsigned long)decrypt_data_size); TPM_PrintFourLimit(" TPM_RSAPublicEncrypt_Common: Decrypt data", decrypt_data, decrypt_data_size); /* check the key size vs the data size */ if (rc == 0) { if (decrypt_data_size > nbytes) { printf("TPM_RSAPublicEncrypt_Common: Error, data size too long for key size %u bytes\n", nbytes); rc = TPM_BAD_DATASIZE; } } /* allocate an array for the encrypted data */ if (rc == 0) { rc = TPM_Malloc(&encrypt_data, nbytes); } /* pad and encrypt the data */ if (rc == 0) { TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Public key", narr); printf(" TPM_RSAPublicEncrypt_Common: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ nbytes, /* encrypted data size */ encScheme, /* encryption scheme */ decrypt_data, /* decrypted data */ decrypt_data_size, narr, /* public modulus */ nbytes, earr, /* public exponent */ ebytes); } /* copy the result to the sized buffer */ if (rc == 0) { printf(" TPM_RSAPublicEncrypt_Common: Encrypt data size %u\n", nbytes); TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Encrypt data", encrypt_data); rc = TPM_SizedBuffer_Set(enc_data, nbytes, encrypt_data); } free(encrypt_data); /* @1 */ return rc; } /* Signing Functions These commands show the TPM command and the allowed signature schemes: SHA DER INFO TPM_GetAuditDigestSigned y n y TPM_CertifyKey y n y TPM_CertifyKey2 y n y TPM_CertifySelfTest y n y TPM_Quote y n y TPM_Quote2 y n y TPM_Sign y y y TPM_MakeIdentity y n y TPM_GetCapabilitySigned y n y */ /* TPM_RSASignToSizedBuffer() signs 'message' using the private key in 'tpm_key' and places the result in 'signature' 'signature' should be initialized and deleted by the caller */ TPM_RESULT TPM_RSASignToSizedBuffer(TPM_SIZED_BUFFER *signature, const unsigned char *message, /* input */ size_t message_size, /* input */ TPM_KEY *tpm_key) /* input, signing key */ { TPM_RESULT rc = 0; TPM_RSA_KEY_PARMS *rsa_key_parms; unsigned int signature_length; printf(" TPM_RSASignToSizedBuffer: Message size %lu bytes\n", (unsigned long)message_size); if (rc == 0) { rc = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, &(tpm_key->algorithmParms)); } /* allocating space for the signature */ if (rc == 0) { rc = TPM_SizedBuffer_Allocate(signature, (rsa_key_parms->keyLength)/CHAR_BIT); } /* sign */ if (rc == 0) { rc = TPM_RSASignH(signature->buffer, /* output signature */ &signature_length, /* output, size of signature */ signature->size, /* input, size of signature buffer */ message, /* message */ message_size, /* message size */ tpm_key); /* input, signing key */ } /* sanity check on signature */ if (rc == 0) { if (signature_length != signature->size) { printf("TPM_RSASignToSizedBuffer: Error (fatal) signature_length %u sigSize %u\n", signature_length, signature->size); rc = TPM_FAIL; /* internal error, should never occur */ } } return rc; } /* TPM_RSASignH() signs 'message' using the private key in 'tpm_key'. 'signature_length' bytes are moved to 'signature'. 'signature_length' is at most 'signature_size'. */ TPM_RESULT TPM_RSASignH(unsigned char *signature, /* output */ unsigned int *signature_length, /* output, size of signature */ unsigned int signature_size, /* input, size of signature buffer */ const unsigned char *message, /* input */ size_t message_size, /* input */ TPM_KEY *tpm_key) /* input, signing key */ { TPM_RESULT rc = 0; unsigned char *narr; /* public modulus */ uint32_t nbytes; unsigned char *earr; /* public exponent */ uint32_t ebytes; unsigned char *darr; /* private exponent */ uint32_t dbytes; printf(" TPM_RSASignH: Message size %lu bytes\n", (unsigned long)message_size); TPM_PrintFourLimit(" TPM_RSASignH: Message", message, message_size); /* extract the public key from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); } /* extract the private key from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); } /* extract the exponent from TPM_KEY */ if (rc == 0) { rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); } if (rc == 0) { /* debug printing */ TPM_PrintFour(" TPM_RSASignH: Public key", narr); printf(" TPM_RSASignH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); TPM_PrintFour(" TPM_RSASignH: Private key", darr); /* sign with private key */ rc = TPM_RSASign(signature, /* output */ signature_length, /* output, size of signature */ signature_size, /* input, size of signature buffer */ tpm_key->algorithmParms.sigScheme, /* input, type of signature */ message, /* input */ message_size, /* input */ narr, /* public modulus */ nbytes, earr, /* public exponent */ ebytes, darr, /* private exponent */ dbytes); } if (rc == 0) { TPM_PrintFour(" TPM_RSASignH: Signature", signature); } return rc; } /* TPM_RSAVerifyH() verifies 'message' using the TPM format public key in 'tpm_pubkey' */ TPM_RESULT TPM_RSAVerifyH(TPM_SIZED_BUFFER *signature, /* input */ const unsigned char *message, /* input */ uint32_t message_size, /* input */ TPM_PUBKEY *tpm_pubkey) /* input, verify key */ { TPM_RESULT rc = 0; unsigned char *narr; /* public modulus */ uint32_t nbytes; unsigned char *earr; /* public exponent */ uint32_t ebytes; printf(" TPM_RSAVerifyH: Message size %u bytes\n", message_size); /* extract the public key from TPM_PUBKEY */ if (rc == 0) { rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); } /* extract the exponent from TPM_PUBKEY */ if (rc == 0) { rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); } if (rc == 0) { /* debug printing */ TPM_PrintFour(" TPM_RSAVerifyH: Public key", narr); TPM_PrintAll(" TPM_RSAVerifyH: Public exponent", earr, ebytes); /* verify with public key */ rc = TPM_RSAVerify(signature->buffer, /* input signature buffer */ signature->size, /* input, size of signature buffer */ tpm_pubkey->algorithmParms.sigScheme, /* input, type of signature */ message, /* message */ message_size, /* message size */ narr, /* public modulus */ nbytes, earr, /* public exponent */ ebytes); } return rc; } /* TPM_RSAVerify() verifies the 'signature' of size 'signature_size' on the 'message' of size 'message_size' using the public key n,e and the signature scheme 'sigScheme' as specified in PKCS #1 v2.0. */ TPM_RESULT TPM_RSAVerify(unsigned char *signature, /* input */ unsigned int signature_size, /* input, size of signature buffer */ TPM_SIG_SCHEME sigScheme, /* input, type of signature */ const unsigned char *message, /* input */ uint32_t message_size, /* input */ unsigned char *narr, /* public modulus */ uint32_t nbytes, unsigned char *earr, /* public exponent */ uint32_t ebytes) { TPM_RESULT rc = 0; printf(" TPM_RSAVerify:\n"); /* determine the signature scheme for the key */ if (rc == 0) { switch(sigScheme) { case TPM_SS_NONE: printf("TPM_RSAVerify: Error, sigScheme TPM_SS_NONE\n"); rc = TPM_INVALID_KEYUSAGE; break; case TPM_SS_RSASSAPKCS1v15_SHA1: case TPM_SS_RSASSAPKCS1v15_INFO: rc = TPM_RSAVerifySHA1(signature, signature_size, message, message_size, narr, /* public modulus */ nbytes, earr, /* public exponent */ ebytes); break; case TPM_SS_RSASSAPKCS1v15_DER: printf("TPM_RSAVerify: Error, sigScheme %04hx unsupported\n", sigScheme); rc = TPM_INVALID_KEYUSAGE; break; default: printf("TPM_RSAVerify: Error, sigScheme %04hx unknown\n", sigScheme); rc = TPM_INVALID_KEYUSAGE; break; } } return rc; } /* OAEP Padding */ /* TPM_RSA_padding_add_PKCS1_OAEP() is a variation of the the openSSL function int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, unsigned char *f, int fl, unsigned char *p, int pl); It is used for TPM migration. The "encoding parameter" pl is replaced by pHash and the generated random seed is replaced by a seed parameter. This function was independently written from the PKCS1 specification "9.1.1.1 Encoding Operation", intended to be unencumbered by any license. | seed | pHash | PS | 01 | Message | SHA1 SHA1 flen | <- emLen -> | | db | maskDb | dbMask | | seedMask | maskSeed */ TPM_RESULT TPM_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen, const unsigned char *from, uint32_t fLen, const unsigned char *pHash, /* input 20 bytes */ const unsigned char *seed) /* input 20 bytes */ { TPM_RESULT rc = 0; unsigned char *dbMask; unsigned char *db; unsigned char *maskedDb; unsigned char *seedMask; unsigned char *maskedSeed; printf(" TPM_RSA_padding_add_PKCS1_OAEP: fLen %d emLen %d\n", fLen, emLen); TPM_PrintFourLimit(" TPM_RSA_padding_add_PKCS1_OAEP: from", from, fLen); TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: pHash", pHash); TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: seed", seed); dbMask = NULL; /* freed @1 */ /* 1. If the length of P is greater than the input limitation for */ /* the hash function (2^61-1 octets for SHA-1) then output "parameter */ /* string too long" and stop. */ /* NOTE Not done, pHash is input directly */ /* 2. If ||M|| > emLen-2hLen-1 then output "message too long" and stop. */ if (rc == 0) { if (emLen < ((2 * TPM_DIGEST_SIZE) + 1 + fLen)) { printf("TPM_RSA_padding_add_PKCS1_OAEP: Error, " "message length %u too large for encoded length %u\n", fLen, emLen); rc = TPM_ENCRYPT_ERROR; } } /* 3. Generate an octet string PS consisting of emLen-||M||-2hLen-1 zero octets. The length of PS may be 0. */ /* NOTE Created directly in DB (step 5) */ /* 4. Let pHash = Hash(P), an octet string of length hLen. */ /* NOTE pHash is input directly */ /* 5. Concatenate pHash, PS, the message M, and other padding to form a data block DB as: DB = pHash || PS || 01 || M */ if (rc == 0) { /* NOTE Since db is eventually maskedDb, part of em, create directly in em */ db = em + TPM_DIGEST_SIZE; memcpy(db, pHash, TPM_DIGEST_SIZE); /* pHash */ memset(db + TPM_DIGEST_SIZE, 0, /* PS */ emLen - fLen - (2 * TPM_DIGEST_SIZE) - 1); /* PSlen = emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 0x01 index = TPM_DIGEST_SIZE + PSlen = TPM_DIGEST_SIZE + emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 = emlen - fLen - TPM_DIGEST_SIZE - 1 */ db[emLen - fLen - TPM_DIGEST_SIZE - 1] = 0x01; memcpy(db + emLen - fLen - TPM_DIGEST_SIZE, from, fLen); /* M */ /* 6. Generate a random octet string seed of length hLen. */ /* NOTE seed is input directly */ /* 7. Let dbMask = MGF(seed, emLen-hLen). */ rc = TPM_Malloc(&dbMask, emLen - TPM_DIGEST_SIZE); } if (rc == 0) { rc = TPM_MGF1(dbMask, emLen - TPM_DIGEST_SIZE, seed, TPM_DIGEST_SIZE); } if (rc == 0) { /* 8. Let maskedDB = DB \xor dbMask. */ /* NOTE Since maskedDB is eventually em, XOR directly to em */ maskedDb = em + TPM_DIGEST_SIZE; TPM_XOR(maskedDb, db, dbMask, emLen - TPM_DIGEST_SIZE); /* 9. Let seedMask = MGF(maskedDB, hLen). */ /* NOTE Since seedMask is eventually em, create directly to em */ seedMask = em; rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDb, emLen - TPM_DIGEST_SIZE); } if (rc == 0) { /* 10. Let maskedSeed = seed \xor seedMask. */ /* NOTE Since maskedSeed is eventually em, create directly to em */ maskedSeed = em; TPM_XOR(maskedSeed, seed, seedMask, TPM_DIGEST_SIZE); /* 11. Let EM = maskedSeed || maskedDB. */ /* NOTE Created directly in em */ /* 12. Output EM. */ TPM_PrintFourLimit(" TPM_RSA_padding_add_PKCS1_OAEP: em", em, emLen); } free(dbMask); /* @1 */ return rc; } /* TPM_RSA_padding_check_PKCS1_OAEP() is a variation of the openSSL function int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, unsigned char *f, int fl, int rsa_len, unsigned char *p, int pl); It is used for TPM key migration. In addition to the message 'to' and message length 'tlen', the seed and 'pHash are returned. This function was independently written from the PKCS1 specification "9.1.1.2 Decoding Operation", intended to be unencumbered by the any license. | seed | pHash | PS | 01 | Message | SHA1 SHA1 | <- emLen -> | | maskedSeed | seedMask | maskedDB | db | <- dbMask -> | */ TPM_RESULT TPM_RSA_padding_check_PKCS1_OAEP(unsigned char *to, uint32_t *tLen, uint32_t tSize, const unsigned char *em, uint32_t emLen, unsigned char *pHash, /* output 20 bytes */ unsigned char *seed) /* output 20 bytes */ { TPM_RESULT rc = 0; const unsigned char *maskedSeed; const unsigned char *maskedDB; uint32_t dbLen; unsigned char *dbMask; unsigned char *seedMask; unsigned char *db; size_t i; printf(" TPM_RSA_padding_check_PKCS1_OAEP: emLen %d tSize %d\n", emLen, tSize); TPM_PrintFourLimit(" TPM_RSA_padding_check_PKCS1_OAEP: em", em, emLen); dbMask = NULL; /* freed @1 */ /* 1. If the length of P is greater than the input limitation for the hash function (2^61-1 octets for SHA-1) then output "parameter string too long" and stop. */ /* NOTE There is no P input. pHash is calculated for the output, but no comparison is performed. */ /* 2. If ||EM|| < 2hLen+1, then output "decoding error" and stop. */ if (rc == 0) { if (emLen < (2 * TPM_DIGEST_SIZE) + 1) { printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, encoded length %u too small\n", emLen); rc = TPM_DECRYPT_ERROR; } } if (rc == 0) { /* 3. Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining ||EM|| - hLen octets. */ maskedSeed = em; maskedDB = em + TPM_DIGEST_SIZE; dbLen = emLen - TPM_DIGEST_SIZE; /* 4. Let seedMask = MGF(maskedDB, hLen). */ /* NOTE Created directly in seed */ seedMask = seed; rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDB, dbLen); } if (rc == 0) { /* 5. Let seed = maskedSeed \xor seedMask. */ TPM_XOR(seed, maskedSeed, seedMask, TPM_DIGEST_SIZE); /* 6. Let dbMask = MGF(seed, ||EM|| - hLen). */ rc = TPM_Malloc(&dbMask, dbLen); } if (rc == 0) { rc = TPM_MGF1(dbMask, dbLen, seed, TPM_DIGEST_SIZE); } if (rc == 0) { /* 7. Let DB = maskedDB \xor dbMask. */ /* NOTE XOR back to dbMask, since dbMask no longer needed */ db = dbMask; TPM_XOR(db, maskedDB, dbMask, dbLen); /* 8. Let pHash = Hash(P), an octet string of length hLen. */ /* NOTE pHash is input directly */ /* 9. Separate DB into an octet string pHash' consisting of the first hLen octets of DB, ... */ memcpy(pHash, db, TPM_DIGEST_SIZE); /* ... a (possibly empty) octet string PS consisting of consecutive zero octets following pHash', and a message M as: DB = pHash' || PS || 01 || M */ for (i = TPM_DIGEST_SIZE; i < dbLen; i++) { if (db[i] != 0x00) { break; /* skip the PS segment */ } } /* If there is no 01 octet to separate PS from M, output "decoding error" and stop. */ if (i == dbLen) { printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); rc = TPM_DECRYPT_ERROR; } } if (rc == 0) { if (db[i] != 0x01) { printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); rc = TPM_DECRYPT_ERROR; } } /* 10. If pHash' does not equal pHash, output "decoding error" and stop. */ /* NOTE No pHash input to compare */ /* 11. Output M. */ if (rc == 0) { i++; /* skip the 0x01 to the beginning of the message M */ *tLen = dbLen - i; if (*tLen > tSize) { printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, tSize %u too small for message %u\n", tSize, *tLen); rc = TPM_DECRYPT_ERROR; } } if (rc == 0) { memcpy(to, db + i, *tLen); printf(" TPM_RSA_padding_check_PKCS1_OAEP: tLen %d \n", *tLen); TPM_PrintFourLimit(" TPM_RSA_padding_check_PKCS1_OAEP: to", to, *tLen); TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: pHash", pHash); TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: seed", seed); } free(dbMask); /* @1 */ return rc; } /* TPM_RSA_exponent_verify() validates the public exponent against a list of legal values. Some values (e.g. even numbers) will have the key generator. */ TPM_RESULT TPM_RSA_exponent_verify(unsigned long exponent) { TPM_RESULT rc = 0; size_t i; int found; static const unsigned long legalExponent[] = { 3,5,7,17,257,65537 }; for (i = 0, found = FALSE ; !found && (i < (sizeof(legalExponent) / sizeof (unsigned long))) ; i++) { if (exponent == legalExponent[i]) { found = TRUE; } } if (!found) { printf("TPM_RSA_exponent_verify: Error, public exponent %lu is illegal\n", exponent ); rc = TPM_BAD_KEY_PROPERTY; } return rc; } /* SHA1 and HMAC test driver Returns TPM_FAILEDSELFTEST on error */ TPM_RESULT TPM_CryptoTest(void) { TPM_RESULT rc = 0; int not_equal; TPM_BOOL valid; /* SHA1 */ unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, 0x3B,0xD2,0x6E,0xBA,0xAE, 0x4A,0xA1,0xF9,0x51,0x29, 0xE5,0xE5,0x46,0x70,0xF1}; TPM_DIGEST actual; uint32_t actual_size; /* HMAC */ unsigned char key2[] = {0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa}; unsigned char expect2[] = {0x12,0x5d,0x73,0x42,0xb9,0xac,0x11,0xcd,0x91,0xa3, 0x9a,0xf4,0x8a,0xa1,0x7b,0x4f,0x63,0xf1,0x75,0xd3}; /* data 0xdd repeated 50 times */ unsigned char data2[50]; /* oaep tests */ const unsigned char oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; unsigned char pHash_in[TPM_DIGEST_SIZE]; unsigned char pHash_out[TPM_DIGEST_SIZE]; unsigned char seed_in[TPM_DIGEST_SIZE] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, 0xf0,0xf1,0xf2,0xf3}; unsigned char seed_out[TPM_DIGEST_SIZE]; unsigned char oaep_in[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; unsigned char oaep_pad[256]; unsigned char oaep_out[8]; uint32_t oeap_length; /* symmetric key with pad */ TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data = NULL; /* opaque structure, freed @7 */ unsigned char clrStream[64]; /* expected */ unsigned char *encStream; /* encrypted */ uint32_t encSize; unsigned char *decStream; /* actual */ uint32_t decSize; /* symmetric key ctr and ofb mode */ TPM_SECRET symKey; TPM_NONCE pad; /* CTR or IV */ TPM_ENCAUTH symClear; TPM_ENCAUTH symEnc; TPM_ENCAUTH symDec; /* RSA encrypt and decrypt, sign and verify */ unsigned char *n; /* public key - modulus */ unsigned char *p; /* private key prime */ unsigned char *q; /* private key prime */ unsigned char *d; /* private key (private exponent) */ unsigned char encrypt_data[2048/8]; /* encrypted data */ unsigned char signature[2048/8]; /* signature; libtpms added */ printf(" TPM_CryptoTest:\n"); encStream = NULL; /* freed @1 */ decStream = NULL; /* freed @2 */ n = NULL; /* freed @3 */ p = NULL; /* freed @4 */ q = NULL; /* freed @5 */ d = NULL; /* freed @6 */ if (rc == 0) { printf(" TPM_CryptoTest: Test 1 - SHA1 one part\n"); rc = TPM_SHA1(actual, sizeof(buffer1) - 1, buffer1, 0, NULL); } if (rc == 0) { not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); if (not_equal) { printf("TPM_CryptoTest: Error in test 1\n"); TPM_PrintFour("\texpect", expect1); TPM_PrintFour("\tactual", actual); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 2 - SHA1 two parts\n"); rc = TPM_SHA1(actual, 16, buffer1, /* first 16 */ sizeof(buffer1) - 17, buffer1 + 16, /* rest */ 0, NULL); } if (rc == 0) { not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); if (not_equal) { printf("TPM_CryptoTest: Error in test 2\n"); TPM_PrintFour("\texpect", expect1); TPM_PrintFour("\tactual", actual); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 3 - HMAC generate - one part\n"); memset(data2, 0xdd, 50); rc = TPM_HMAC_Generate(actual, key2, 50, data2, 0, NULL); } if (rc == 0) { not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); if (not_equal) { printf("TPM_CryptoTest: Error in test 3\n"); TPM_PrintFour("\texpect", expect1); TPM_PrintFour("\tactual", actual); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 4 - HMAC generate - two parts\n"); memset(data2, 0xdd, 50); rc = TPM_HMAC_Generate(actual, key2, 20, data2, 30, data2 + 20, 0, NULL); } if (rc == 0) { not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); if (not_equal) { printf("TPM_CryptoTest: Error in test 3\n"); TPM_PrintFour("\texpect", expect2); TPM_PrintFour("\tactual", actual); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 4 - HMAC check - two parts\n"); memset(data2, 0xdd, 50); rc = TPM_HMAC_Check(&valid, expect2, key2, 20, data2, 30, data2 + 20, 0, NULL); } if (rc == 0) { if (!valid) { printf("TPM_CryptoTest: Error in test 4\n"); TPM_PrintFour("\texpect", expect1); TPM_PrintFour("\tactual", actual); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 5 - OAEP add and check\n"); rc = TPM_SHA1(pHash_in, sizeof(oaep_pad_str), oaep_pad_str, 0, NULL); } if (rc == 0) { rc = TPM_RSA_padding_add_PKCS1_OAEP(oaep_pad, sizeof(oaep_pad), oaep_in, sizeof(oaep_in), pHash_in, seed_in); } if (rc == 0) { rc = TPM_RSA_padding_check_PKCS1_OAEP(oaep_out, &oeap_length, sizeof(oaep_out), oaep_pad, sizeof(oaep_pad), pHash_out, seed_out); } if (rc == 0) { if (oeap_length != sizeof(oaep_out)) { printf("TPM_CryptoTest: Error in test 5, expect length %lu, actual length %u\n", (unsigned long)sizeof(oaep_out), oeap_length); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { not_equal = memcmp(oaep_in, oaep_out, sizeof(oaep_out)); if (not_equal) { printf("TPM_CryptoTest: Error in test 5 oaep\n"); TPM_PrintFour("\tin ", oaep_in); TPM_PrintFour("\tout", oaep_out); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { not_equal = memcmp(pHash_in, pHash_out, sizeof(pHash_in)); if (not_equal) { printf("TPM_CryptoTest: Error in test 5 pHash\n"); TPM_PrintFour("\tpHash_in ", pHash_in); TPM_PrintFour("\tpHash_out", pHash_out); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { not_equal = memcmp(seed_in, seed_out, sizeof(seed_in)); if (not_equal) { printf("TPM_CryptoTest: Error in test 5 seed\n"); TPM_PrintFour("\tseed_in ", seed_in); TPM_PrintFour("\tseed_out", seed_out); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 6 - Symmetric key with PKCS pad test\n"); /* allocate memory for the key token */ rc = TPM_SymmetricKeyData_New(&tpm_symmetric_key_data); /* freed @7 */ } /* generate a key */ if (rc == 0) { rc = TPM_SymmetricKeyData_GenerateKey(tpm_symmetric_key_data); } /* generate clear text */ if (rc == 0) { rc = TPM_Random(clrStream, sizeof(clrStream)); } /* symmetric encrypt */ if (rc == 0) { rc = TPM_SymmetricKeyData_Encrypt(&encStream, /* output, freed @1 */ &encSize, /* output */ clrStream, /* input */ sizeof(clrStream), /* input */ tpm_symmetric_key_data); /* key */ } /* symmetric decrypt */ if (rc == 0) { rc = TPM_SymmetricKeyData_Decrypt(&decStream, /* output, freed by caller */ &decSize, /* output */ encStream, /* input */ encSize, /* input */ tpm_symmetric_key_data); /* key */ } /* symmetric compare */ if (rc == 0) { if (sizeof(clrStream) != decSize) { printf("TPM_CryptoTest: Error in test 6, in %lu, out %u\n", (unsigned long)sizeof(clrStream), decSize); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { not_equal = memcmp(clrStream, decStream, sizeof(clrStream)); if (not_equal) { printf("TPM_CryptoTest: Error in test 6\n"); TPM_PrintFour("\tclear stream in", clrStream); TPM_PrintFour("\tdecrypted stream", decStream); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { printf(" TPM_CryptoTest: Test 7 - Symmetric key with CTR mode\n"); /* generate a key */ rc = TPM_Random(symKey, TPM_SECRET_SIZE); } /* generate CTR */ if (rc == 0) { rc = TPM_Random(pad, TPM_NONCE_SIZE); } /* generate clear text */ if (rc == 0) { rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); } if (rc == 0) { rc = TPM_SymmetricKeyData_CtrCrypt(symEnc, /* output */ symClear, /* input */ TPM_AUTHDATA_SIZE, /* input */ symKey, /* in */ TPM_SECRET_SIZE, /* in */ pad, /* input */ TPM_NONCE_SIZE); /* input */ } if (rc == 0) { rc = TPM_SymmetricKeyData_CtrCrypt(symDec, /* output */ symEnc, /* input */ TPM_AUTHDATA_SIZE, /* input */ symKey, /* in */ TPM_SECRET_SIZE, /* in */ pad, /* input */ TPM_NONCE_SIZE); /* input */ } /* symmetric compare */ if (rc == 0) { rc = TPM_Secret_Compare(symDec, symClear); if (rc != 0) { printf("TPM_CryptoTest: Error in test 8\n"); TPM_PrintFour("\tclear stream in", symClear); TPM_PrintFour("\tdecrypted stream", symDec); } } if (rc == 0) { printf(" TPM_CryptoTest: Test 8 - Symmetric key with OFB mode\n"); /* generate a key */ rc = TPM_Random(symKey, TPM_SECRET_SIZE); } /* generate IV */ if (rc == 0) { rc = TPM_Random(pad, TPM_NONCE_SIZE); } /* generate clear text */ if (rc == 0) { rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); } if (rc == 0) { rc = TPM_SymmetricKeyData_OfbCrypt(symEnc, /* output */ symClear, /* input */ TPM_AUTHDATA_SIZE, /* input */ symKey, /* in */ TPM_SECRET_SIZE, /* in */ pad, /* input */ TPM_NONCE_SIZE); /* input */ } if (rc == 0) { rc = TPM_SymmetricKeyData_OfbCrypt(symDec, /* output */ symEnc, /* input */ TPM_AUTHDATA_SIZE, /* input */ symKey, /* in */ TPM_SECRET_SIZE, /* in */ pad, /* input */ TPM_NONCE_SIZE); /* input */ } /* symmetric compare */ if (rc == 0) { rc = TPM_Secret_Compare(symDec, symClear); if (rc != 0) { printf("TPM_CryptoTest: Error in test 8\n"); TPM_PrintFour("\tclear stream in", symClear); TPM_PrintFour("\tdecrypted stream", symDec); } } /* RSA OAEP encrypt and decrypt */ if (rc == 0) { printf(" TPM_CryptoTest: Test 9 - RSA encrypt with OAEP padding\n"); /* generate a key */ rc = TPM_RSAGenerateKeyPair(&n, /* public key - modulus */ &p, /* private key prime */ &q, /* private key prime */ &d, /* private key (private exponent) */ 2048, /* key size in bits */ tpm_default_rsa_exponent, /* public exponent as an array */ 3); } /* encrypt */ if (rc == 0) { rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ sizeof(encrypt_data), /* size of encrypted data buffer */ TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ expect1, /* decrypted data */ sizeof(expect1), n, /* public modulus */ 2048/8, tpm_default_rsa_exponent, /* public exponent */ 3); } if (rc == 0) { rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ &actual_size, /* length of data put into decrypt_data */ TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ encrypt_data, /* encrypted data */ sizeof(encrypt_data), n, /* public modulus */ 2048/8, tpm_default_rsa_exponent, /* public exponent */ 3, d, /* private exponent */ 2048/8); } if (rc == 0) { if (actual_size != TPM_DIGEST_SIZE) { printf("TPM_CryptoTest: Error in test 9, expect length %u, actual length %u\n", TPM_DIGEST_SIZE, actual_size); rc = TPM_FAILEDSELFTEST; } } if (rc == 0) { not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); if (not_equal) { printf("TPM_CryptoTest: Error in test 9\n"); TPM_PrintFour("\tin ", expect1); TPM_PrintFour("\tout", actual); rc = TPM_FAILEDSELFTEST; } } /* RSA PKCS1 pad, encrypt and decrypt */ if (rc == 0) { printf(" TPM_CryptoTest: Test 10 - RSA encrypt with PKCS padding\n"); /* encrypt */ rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ sizeof(encrypt_data), /* size of encrypted data buffer */ TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ expect1, /* decrypted data */ sizeof(expect1), n, /* public modulus */ 2048/8, tpm_default_rsa_exponent, /* public exponent */ 3); } /* decrypt */ if (rc == 0) { rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ &actual_size, /* length of data put into decrypt_data */ TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ encrypt_data, /* encrypted data */ sizeof(encrypt_data), n, /* public modulus */ 2048/8, tpm_default_rsa_exponent, /* public exponent */ 3, d, /* private exponent */ 2048/8); } /* check length after padding removed */ if (rc == 0) { if (actual_size != TPM_DIGEST_SIZE) { printf("TPM_CryptoTest: Error in test 10, expect length %u, actual length %u\n", TPM_DIGEST_SIZE, actual_size); rc = TPM_FAILEDSELFTEST; } } /* check data */ if (rc == 0) { not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); if (not_equal) { printf("TPM_CryptoTest: Error in test 10\n"); TPM_PrintFour("\tin ", expect1); TPM_PrintFour("\tout", actual); rc = TPM_FAILEDSELFTEST; } } // libtpms added begin if (rc == 0) { printf(" TPM_CryptoTest: Test 11a - RSA sign with PKCS1v15 padding\n"); rc = TPM_RSASign(signature, &actual_size, sizeof(signature), TPM_SS_RSASSAPKCS1v15_SHA1, expect1, sizeof(expect1), n, /* public modulus */ 2048/8, tpm_default_rsa_exponent, /* public exponent */ 3, d, /* private exponent */ 2048/8); } if (rc == 0) { rc = TPM_RSAVerify(signature, /* input signature buffer */ sizeof(signature), /* input, size of signature buffer */ TPM_SS_RSASSAPKCS1v15_SHA1, /* input, type of signature */ expect1, /* message */ sizeof(expect1), /* message size */ n, /* public modulus */ 2048/8, tpm_default_rsa_exponent,/* public exponent */ 3); } #if 0 /* Verification with TPM_SS_RSASSAPKCS1v15_DER is not supported */ if (rc == 0) { printf(" TPM_CryptoTest: Test 11b - RSA sign with PKCS1v15_DER padding\n"); rc = TPM_RSASign(signature, &actual_size, sizeof(signature), TPM_SS_RSASSAPKCS1v15_DER, expect1, sizeof(expect1), n, /* public modulus */ 2048/8, tpm_default_rsa_exponent, /* public exponent */ 3, d, /* private exponent */ 2048/8); } if (rc == 0) { rc = TPM_RSAVerify(signature, /* input signature buffer */ sizeof(signature), /* input, size of signature buffer */ TPM_SS_RSASSAPKCS1v15_DER, /* input, type of signature */ expect1, /* message */ sizeof(expect1), /* message size */ n, /* public modulus */ 2048/8, tpm_default_rsa_exponent,/* public exponent */ 3); } #endif // libtpms added end /* run library specific self tests as required */ if (rc == 0) { rc = TPM_Crypto_TestSpecific(); } if (rc != 0) { rc = TPM_FAILEDSELFTEST; } free(encStream); /* @1 */ free(decStream); /* @2 */ free(n); /* @3 */ free(p); /* @4 */ free(q); /* @5 */ free(d); /* @6 */ TPM_SymmetricKeyData_Free(&tpm_symmetric_key_data); /* @7 */ return rc; } /* 13.5 TPM_Sign rev 111 The Sign command signs data and returns the resulting digital signature. The TPM does not allow TPM_Sign with a TPM_KEY_IDENTITY (AIK) because TPM_Sign can sign arbitrary data and could be used to fake a quote. (This could have been relaxed to allow TPM_Sign with an AIK if the signature scheme is _INFO For an _INFO key, the metadata prevents TPM_Sign from faking a quote.) The TPM MUST support all values of areaToSignSize that are legal for the defined signature scheme and key size. The maximum value of areaToSignSize is determined by the defined signature scheme and key size. In the case of PKCS1v15_SHA1 the areaToSignSize MUST be TPM_DIGEST (the hash size of a sha1 operation - see 8.5.1 TPM_SS_RSASSAPKCS1v15_SHA1). In the case of PKCS1v15_DER the maximum size of areaToSign is k - 11 octets, where k is limited by the key size (see 8.5.2 TPM_SS_RSASSAPKCS1v15_DER). */ TPM_RESULT TPM_Process_Sign(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform digital signatures. */ TPM_SIZED_BUFFER areaToSign; /* The value to sign */ TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle authorization */ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization handle */ TPM_AUTHDATA privAuth; /* The authorization digest that authorizes the use of keyHandle. HMAC key: key.usageAuth */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus ; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ TPM_BOOL authHandleValid = FALSE; TPM_SECRET *hmacKey; TPM_KEY *key = NULL; /* the key specified by keyHandle */ TPM_RSA_KEY_PARMS *rsa_key_parms; /* for key */ TPM_BOOL parentPCRStatus; TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ TPM_SECRET *keyUsageAuth; TPM_SIGN_INFO tpm_sign_info; const unsigned char *S1_data; /* data to be signed */ uint32_t S1_size; TPM_DIGEST infoDigest; /* TPM_SIGN_INFO structure digest */ TPM_STORE_BUFFER sbuffer; /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ printf("TPM_Process_Sign: Ordinal Entry\n"); TPM_SizedBuffer_Init(&areaToSign); /* freed @1 */ TPM_SignInfo_Init(&tpm_sign_info); /* freed @2 */ TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ TPM_SizedBuffer_Init(&sig); /* freed @4 */ /* get inputs */ /* get keyHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); } /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; if (returnCode == TPM_SUCCESS) { printf("TPM_Process_Sign: keyHandle %08x\n", keyHandle); /* get areaToSignSize and areaToSign parameters */ returnCode = TPM_SizedBuffer_Load(&areaToSign, &command, ¶mSize); /* freed @1 */ } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_Sign: Signing %u bytes\n", areaToSign.size); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag10(tag); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthParams_Get(&authHandle, &authHandleValid, nonceOdd, &continueAuthSession, privAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_Sign: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* do not terminate sessions if the command did not parse correctly */ if (returnCode != TPM_SUCCESS) { authHandleValid = FALSE; } /* Processing */ /* get the key corresponding to the keyHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, FALSE, /* not r/o, used to sign */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } /* check TPM_AUTH_DATA_USAGE authDataUsage */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { if (key->authDataUsage != TPM_AUTH_NEVER) { printf("TPM_Process_Sign: Error, authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* get keyHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); } /* get the session data */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, key, keyUsageAuth, /* OIAP */ key->tpm_store_asymkey->pubDataDigest); /* OSAP */ } /* 1. The TPM validates the AuthData to use the key pointed to by keyHandle. */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, privAuth); /* Authorization digest for input */ } /* 2. If the areaToSignSize is 0 the TPM returns TPM_BAD_PARAMETER. */ if (returnCode == TPM_SUCCESS) { if (areaToSign.size == 0) { printf("TPM_Process_Sign: Error, areaToSignSize is 0\n"); returnCode = TPM_BAD_PARAMETER; } } /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ if (returnCode == TPM_SUCCESS) { if ((key->keyUsage != TPM_KEY_SIGNING) && ((key->keyUsage) != TPM_KEY_LEGACY)) { printf("TPM_Process_Sign: Error, keyUsage %04hx is invalid\n", key->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 4. The TPM verifies that the signature scheme and key size can properly sign the areaToSign parameter. NOTE Done in 5. - 7.*/ /* get key -> TPM_RSA_KEY_PARMS */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, &(key->algorithmParms)); } if (returnCode == TPM_SUCCESS) { /* 5. If signature scheme is TPM_SS_RSASSAPKCS1v15_SHA1 then */ if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1\n"); /* a. Validate that areaToSignSize is 20 return TPM_BAD_PARAMETER on error */ if (returnCode == TPM_SUCCESS) { if (areaToSign.size != TPM_DIGEST_SIZE) { printf("TPM_Process_Sign: Error, areaToSignSize %d should be %u\n", areaToSign.size, TPM_DIGEST_SIZE); returnCode = TPM_BAD_PARAMETER; } } /* b. Set S1 to areaToSign */ if (returnCode == TPM_SUCCESS) { S1_size = areaToSign.size; S1_data = areaToSign.buffer; } } /* 6. Else if signature scheme is TPM_SS_RSASSAPKCS1v15_DER then */ else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_DER) { printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_DER\n"); /* a. Validate that areaToSignSize is at least 11 bytes less than the key size, return TPM_BAD_PARAMETER on error */ if (returnCode == TPM_SUCCESS) { if (areaToSign.size > (((rsa_key_parms->keyLength)/CHAR_BIT) - 11)) { printf("TPM_Process_Sign: Error, areaToSignSize %d should be 11-%u\n", areaToSign.size, ((rsa_key_parms->keyLength)/CHAR_BIT)); returnCode = TPM_BAD_PARAMETER; } } /* b. Set S1 to areaToSign */ if (returnCode == TPM_SUCCESS) { S1_size = areaToSign.size; S1_data = areaToSign.buffer; } } /* 7. else if signature scheme is TPM_SS_RSASSAPKCS1v15_INFO then */ else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) { printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_INFO\n"); if (returnCode == TPM_SUCCESS) { /* a. Create S2 a TPM_SIGN_INFO structure */ /* NOTE: Done by TPM_SignInfo_Init() */ /* b. Set S2 -> fixed to "SIGN" */ memcpy(tpm_sign_info.fixed, "SIGN", TPM_SIGN_INFO_FIXED_SIZE); /* c.i. If nonceOdd is not present due to an unauthorized command return TPM_BAD_PARAMETER */ if (tag == TPM_TAG_RQU_COMMAND) { printf("TPM_Process_Sign: Error, TPM_SS_RSASSAPKCS1v15_INFO and no auth\n"); returnCode = TPM_BAD_PARAMETER; } } if (returnCode == TPM_SUCCESS) { /* c. Set S2 -> replay to nonceOdd */ TPM_Nonce_Copy(tpm_sign_info.replay, nonceOdd); /* d. Set S2 -> dataLen to areaToSignSize */ /* e. Set S2 -> data to areaToSign */ returnCode = TPM_SizedBuffer_Copy(&(tpm_sign_info.data), &areaToSign); } /* f. Set S1 to the SHA-1(S2) */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1_GenerateStructure(infoDigest, &tpm_sign_info, (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); S1_size = TPM_DIGEST_SIZE; S1_data = infoDigest; } } /* 8. Else return TPM_INVALID_KEYUSAGE */ else { printf("TPM_Process_Sign: Error, sigScheme %04hx\n", key->algorithmParms.sigScheme); returnCode = TPM_INVALID_KEYUSAGE; } } /* 9. The TPM computes the signature, sig, using the key referenced by keyHandle using S1 as the value to sign */ if (returnCode == TPM_SUCCESS) { TPM_PrintAll("TPM_Process_Sign: Digest to sign", S1_data, S1_size); returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ S1_data, /* message */ S1_size, /* message size */ key); /* input, signing key */ } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_Sign: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* 10. Return the computed signature in Sig */ returnCode = TPM_SizedBuffer_Store(response, &sig); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* calculate and set the below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *hmacKey, /* owner HMAC key */ auth_session_data, outParamDigest, nonceOdd, continueAuthSession); } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* if there was an error, or continueAuthSession is FALSE, terminate the session */ if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueAuthSession) && authHandleValid) { TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); } /* cleanup */ TPM_SizedBuffer_Delete(&areaToSign); /* @1 */ TPM_SignInfo_Delete(&tpm_sign_info); /* @2 */ TPM_Sbuffer_Delete(&sbuffer); /* @3 */ TPM_SizedBuffer_Delete(&sig); /* @4 */ return rcf; } /* 13.1 TPM_SHA1Start rev 96 This capability starts the process of calculating a SHA-1 digest. The exposure of the SHA-1 processing is a convenience to platforms in a mode that do not have sufficient memory to perform SHA-1 themselves. As such the use of SHA-1 is restrictive on the TPM. The TPM may not allow any other types of processing during the execution of a SHA-1 session. There is only one SHA-1 session active on a TPM. The exclusivity of a SHA-1 context is due to the relatively large volatile buffer it requires in order to hold the intermediate results between the SHA-1 context commands. This buffer can be in contradiction to other command needs. After the execution of SHA1Start, and prior to SHA1End, the receipt of any command other than SHA1Update will cause the invalidation of the SHA-1 session. */ TPM_RESULT TPM_Process_SHA1Start(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters - none */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; uint32_t maxNumBytes = TPM_SHA1_MAXNUMBYTES; /* Maximum number of bytes that can be sent to TPM_SHA1Update. Must be a multiple of 64 bytes. */ printf("TPM_Process_SHA1Start: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | TPM_CHECK_NO_LOCKOUT)); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag0(tag); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_SHA1Start: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* This capability prepares the TPM for a subsequent TPM_SHA1Update, TPM_SHA1Complete or TPM_SHA1CompleteExtend command. The capability SHALL open a thread that calculates a SHA-1 digest. */ if (returnCode == TPM_SUCCESS) { if (transportInternal == NULL) { tpm_state->transportHandle = 0; /* SHA-1 thread not within transport */ } else { tpm_state->transportHandle = transportInternal->transHandle; /* SHA-1 thread within transport */ } returnCode = TPM_SHA1InitCmd(&(tpm_state->sha1_context)); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_SHA1Start: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* append maxNumBytes */ returnCode = TPM_Sbuffer_Append32(response, maxNumBytes); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } return rcf; } /* 13.2 TPM_SHA1Update rev 114 This capability inputs complete blocks of data into a pending SHA-1 digest. At the end of the process, the digest remains pending. */ TPM_RESULT TPM_Process_SHA1Update(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_SIZED_BUFFER hashData; /* Bytes to be hashed */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; printf("TPM_Process_SHA1Update: Ordinal Entry\n"); TPM_SizedBuffer_Init(&hashData); /* freed @1 */ /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* load hashData */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | TPM_CHECK_NO_LOCKOUT)); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag0(tag); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_SHA1Update: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* This command SHALL incorporate complete blocks of data into the digest of an existing SHA-1 thread. Only integral numbers of complete blocks (64 bytes each) can be processed. */ /* 1. If there is no existing SHA-1 thread, return TPM_SHA_THREAD */ if (returnCode == TPM_SUCCESS) { if (tpm_state->sha1_context == NULL) { printf("TPM_Process_SHA1Update: Error, no existing SHA1 thread\n"); returnCode = TPM_SHA_THREAD; } } /* 2. If numBytes is not a multiple of 64 */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_SHA1Update: numBytes %u bytes\n", hashData.size); if ((hashData.size % 64) != 0) { printf("TPM_Process_SHA1Update: Error, numBytes not integral number of blocks\n"); /* a. Return TPM_SHA_ERROR */ returnCode = TPM_SHA_ERROR; /* b. The TPM MAY terminate the SHA-1 thread */ TPM_SHA1Delete(&(tpm_state->sha1_context)); } } /* 3. If numBytes is greater than maxNumBytes returned by TPM_SHA1Start */ if (returnCode == TPM_SUCCESS) { if (hashData.size > TPM_SHA1_MAXNUMBYTES) { /* a. Return TPM_SHA_ERROR */ returnCode = TPM_SHA_ERROR; /* b. The TPM MAY terminate the SHA-1 thread */ TPM_SHA1Delete(&(tpm_state->sha1_context)); } } /* 4. Incorporate hashData into the digest of the existing SHA-1 thread. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1UpdateCmd(tpm_state->sha1_context, hashData.buffer, hashData.size); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_SHA1Update: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* cleanup */ TPM_SizedBuffer_Delete(&hashData); /* @1 */ return rcf; } /* 13.3 TPM_SHA1Complete rev 87 This capability terminates a pending SHA-1 calculation. */ TPM_RESULT TPM_Process_SHA1Complete(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_DIGEST hashValue; /* The output of the SHA-1 hash. */ TPM_SizedBuffer_Init(&hashData); /* freed @1 */ printf("TPM_Process_SHA1Complete: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* load hashData */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | TPM_CHECK_NO_LOCKOUT)); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag0(tag); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_SHA1Complete: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* This command SHALL incorporate a partial or complete block of data into the digest of an existing SHA-1 thread, and terminate that thread. hashDataSize MAY have values in the range of 0 through 64, inclusive. If the SHA-1 thread has received no bytes the TPM SHALL calculate the SHA-1 of the empty buffer. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1CompleteCommon(hashValue, &(tpm_state->sha1_context), &hashData); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_SHA1Complete: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* append hashValue */ returnCode = TPM_Digest_Store(response, hashValue); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* cleanup */ TPM_SizedBuffer_Delete(&hashData); /* @1 */ return rcf; } /* 13.4 TPM_SHA1CompleteExtend rev 109 This capability terminates a pending SHA-1 calculation and EXTENDS the result into a Platform Configuration Register using a SHA-1 hash process. This command is designed to complete a hash sequence and extend a PCR in memory-less environments. This command SHALL incorporate a partial or complete block of data into the digest of an existing SHA-1 thread, EXTEND the resultant digest into a PCR, and terminate the thread. hashDataSize MAY have values in the range of 0 through 64, inclusive. */ TPM_RESULT TPM_Process_SHA1CompleteExtend(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_PCRINDEX pcrNum; /* Index of the PCR to be modified */ TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_DIGEST h1HashValue; /* The output of the SHA-1 hash. */ TPM_PCRVALUE outDigest; /* The PCR value after execution of the command. */ printf("TPM_Process_SHA1CompleteExtend: Ordinal Entry\n"); TPM_SizedBuffer_Init(&hashData); /* freed @1 */ /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get pcrNum */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&pcrNum, &command, ¶mSize); } /* get hashData */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_SHA1CompleteExtend: pcrNum %u\n", pcrNum); returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | TPM_CHECK_NO_LOCKOUT)); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag0(tag); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_SHA1CompleteExtend: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* 1. 1.Validate that pcrNum represents a legal PCR number. On error, return TPM_BADINDEX. */ /* 2. Map V1 to TPM_STANY_DATA */ /* 3. Map L1 to V1 -> localityModifier */ /* 4. If the current locality, held in L1, is not selected in TPM_PERMANENT_DATA -> pcrAttrib [PCRIndex]. pcrExtendLocal, return TPM_BAD_LOCALITY */ /* NOTE Done in TPM_ExtendCommon() */ /* 5. Create H1 the TPM_DIGEST of the SHA-1 session ensuring that hashData, if any, is */ /* added to the SHA-1 session */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1CompleteCommon(h1HashValue, &(tpm_state->sha1_context), &hashData); } /* 6. Perform the actions of TPM_Extend using H1 as the data and pcrNum as the PCR to extend */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_ExtendCommon(outDigest, tpm_state, ordinal, pcrNum, h1HashValue); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_SHA1CompleteExtend: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* append hashValue */ returnCode = TPM_Digest_Store(response, h1HashValue); } /* append outDigest */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Digest_Store(response, outDigest); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* cleanup */ TPM_SizedBuffer_Delete(&hashData); /* @1 */ return rcf; } /* TPM_SHA1CompleteCommon() is common code for TPM_Process_SHA1Complete() and TPM_Process_SHA1CompleteExtend() */ TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, /* output: digest */ void **sha1_context, /* IO: SHA1 context */ TPM_SIZED_BUFFER *hashData) /* final data to be hashed */ { TPM_RESULT rc = 0; /* The TPM specification says that the last data chunk must be 0-64 bytes */ printf("TPM_SHA1CompleteCommon: %u bytes\n", hashData->size); if (rc == 0) { if (hashData->size > 64) { printf("TPM_SHA1CompleteCommon: Error, hashDataSize %u not 0-64\n", hashData->size); rc = TPM_SHA_ERROR; } } /* cannot call SHA1Complete() before SHA1Start() */ if (rc == 0) { if (*sha1_context == NULL) { printf("TPM_SHA1CompleteCommon: Error, no existing SHA1 thread\n"); rc = TPM_SHA_THREAD; } } if ((rc == 0) && (hashData->size != 0)) { rc = TPM_SHA1UpdateCmd(*sha1_context, hashData->buffer, hashData->size); } if (rc == 0) { rc = TPM_SHA1FinalCmd(hashValue, *sha1_context); } /* the SHA1 thread should be terminated even if there is an error */ TPM_SHA1Delete(sha1_context); return rc; } /* 13.6 TPM_GetRandom rev 87 GetRandom returns the next bytesRequested bytes from the random number generator to the caller. It is recommended that a TPM implement the RNG in a manner that would allow it to return RNG bytes such that the frequency of bytesRequested being more than the number of bytes available is an infrequent occurrence. */ TPM_RESULT TPM_Process_GetRandom(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ uint32_t bytesRequested; /* Number of bytes to return */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_SIZED_BUFFER randomBytes; /* The returned bytes */ printf("TPM_Process_GetRandom: Ordinal Entry\n"); TPM_SizedBuffer_Init(&randomBytes); /* freed @1 */ /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get bytesRequested parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&bytesRequested, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag0(tag); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_GetRandom: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* 1. The TPM determines if amount bytesRequested is available from the TPM. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_GetRandom: bytesRequested %u\n", bytesRequested); if (bytesRequested > TPM_RANDOM_MAX) { bytesRequested = TPM_RANDOM_MAX; printf("TPM_Process_GetRandom: bytes available %u\n", bytesRequested); } } /* 2. Set randomBytesSize to the number of bytes available from the RNG. This number MAY be less than bytesRequested. */ if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { returnCode = TPM_SizedBuffer_Allocate(&randomBytes, bytesRequested); } /* 3. Set randomBytes to the next randomBytesSize bytes from the RNG */ if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { returnCode = TPM_Random(randomBytes.buffer, bytesRequested); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_GetRandom: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* append randomBytes */ returnCode = TPM_SizedBuffer_Store(response, &randomBytes); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* cleanup */ TPM_SizedBuffer_Delete(&randomBytes); /* freed @1 */ return rcf; } /* 13.7 TPM_StirRandom rev 109 StirRandom adds entropy to the RNG state. */ TPM_RESULT TPM_Process_StirRandom(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_SIZED_BUFFER inData; /* Data to add entropy to RNG state, Number of bytes of input */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; printf("TPM_Process_StirRandom: Ordinal Entry\n"); TPM_SizedBuffer_Init(&inData); /* freed @1 */ /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get inData parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag0(tag); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_StirRandom: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* 1. If dataSize is not less than 256 bytes, the TPM MAY return TPM_BAD_PARAMETER. */ /* The TPM updates the state of the current RNG using the appropriate mixing function. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_StirRandomCmd(&inData); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_StirRandom: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* cleanup */ TPM_SizedBuffer_Delete(&inData); /* @1 */ return rcf; } /* 13.8 TPM_CertifyKey rev 107 The TPM_CertifyKey operation allows one key to certify the public portion of another key. A TPM identity key may be used to certify non-migratable keys but is not permitted to certify migratory keys or certified migration keys. As such, it allows the TPM to make the statement "this key is held in a TPM-shielded location, and it will never be revealed." For this statement to have veracity, the Challenger must trust the policies used by the entity that issued the identity and the maintenance policy of the TPM manufacturer. Signing and legacy keys may be used to certify both migratable and non-migratable keys. Then the usefulness of a certificate depends on the trust in the certifying key by the recipient of the certificate. The key to be certified must be loaded before TPM_CertifyKey is called. The determination to use the TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 on the output is based on which PCRs and what localities the certified key is restricted to. A key to be certified that does not have locality restrictions and which uses no PCRs greater than PCR #15 will cause this command to return and sign a TPM_CERTIFY_INFO structure, which provides compatibility with V1.1 TPMs. When this command is run to certify all other keys (those that use PCR #16 or higher, as well as those limited by locality in any way), it will return and sign a TPM_CERTIFY_INFO2 structure. TPM_CertifyKey does not support the case where (a) the certifying key requires a usage authorization to be provided but (b) the key-to-be-certified does not. In such cases, TPM_CertifyKey2 must be used. If a command tag (in the parameter array) specifies only one authorisation session, then the TPM convention is that the first session listed is ignored (authDataUsage must be TPM_AUTH_NEVER for this key) and the incoming session data is used for the second auth session in the list. In TPM_CertifyKey, the first session is the certifying key and the second session is the key-to-be-certified. In TPM_CertifyKey2, the first session is the key-to-be-certified and the second session is the certifying key. */ TPM_RESULT TPM_Process_CertifyKey(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_KEY_HANDLE certHandle; /* Handle of the key to be used to certify the key. */ TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce provided to prevent replay-attacks) */ TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle */ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA certAuth; /* The authorization session digest for inputs and certHandle. HMAC key: certKey.auth. */ TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be signed. */ TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle */ TPM_BOOL continueKeySession = TRUE; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key to be signed. HMAC key: key.usageAuth. */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ TPM_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ TPM_BOOL certAuthHandleValid = FALSE; TPM_BOOL keyAuthHandleValid = FALSE; TPM_SECRET *certHmacKey; TPM_SECRET *targetHmacKey; TPM_BOOL certPCRStatus; TPM_BOOL targetPCRStatus; TPM_KEY *certKey = NULL; /* the key specified by certHandle */ TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ TPM_SECRET *certKeyUsageAuth; TPM_SECRET *targetKeyUsageAuth; TPM_BOOL pcrUsage; TPM_LOCALITY_SELECTION localityAtRelease; int v1Version; /* TPM 1.1 or TPM 1.2 */ int certifyType = 0; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 */ TPM_DIGEST m1Digest; /* digest of certifyInfo */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_CERTIFY_INFO certifyInfo; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 structure that provides information relative to keyhandle NOTE This is c1 in the Actions. */ TPM_CERTIFY_INFO2 certifyInfo2; TPM_SIZED_BUFFER outData; /* The signature of certifyInfo */ printf("TPM_Process_CertifyKey: Ordinal Entry\n"); TPM_CertifyInfo_Init(&certifyInfo); /* freed @1 */ TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @2 */ TPM_SizedBuffer_Init(&outData); /* freed @3 */ /* get inputs */ /* get certHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&certHandle, &command, ¶mSize); } /* get keyHandle parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: certHandle %08x\n", certHandle); returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); } /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get antiReplay parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: keyHandle %08x\n", keyHandle); returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag210(tag); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthParams_Get(&certAuthHandle, &certAuthHandleValid, nonceOdd, &continueAuthSession, certAuth, &command, ¶mSize); } if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { printf("TPM_Process_CertifyKey: certAuthHandle %08x\n", certAuthHandle); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_AuthParams_Get(&keyAuthHandle, &keyAuthHandleValid, keynonceOdd, &continueKeySession, keyAuth, &command, ¶mSize); } if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { printf("TPM_Process_CertifyKey: keyAuthHandle %08x\n", keyAuthHandle); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_CertifyKey: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* do not terminate sessions if the command did not parse correctly */ if (returnCode != TPM_SUCCESS) { certAuthHandleValid = FALSE; keyAuthHandleValid = FALSE; } /* Processing */ /* get the key corresponding to the certHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, FALSE, /* not read-only */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } /* get the key corresponding to the keyHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, FALSE, /* not read-only */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ if (returnCode == TPM_SUCCESS) { if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { printf("TPM_Process_CertifyKey: Error, invalid certKey sigScheme %04hx\n", certKey->algorithmParms.sigScheme); returnCode = TPM_BAD_KEY_PROPERTY; } } /* 2. Verify command and key AuthData values */ /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ /* i. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key pointed to by certHandle, return TPM_AUTHFAIL on error */ /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key pointed to by keyHandle, return TPM_AUTH2FAIL on error */ /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return TPM_AUTHFAIL on error. */ /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key pointed to by keyHandle, return TPM_AUTHFAIL on error */ /* c. else if tag is TPM_TAG_RQU_COMMAND */ /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return TPM_AUTHFAIL on error. */ /* ii. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced by keyHandle, return TPM_AUTHFAIL on error. */ /* NOTE: Simplified the above logic as follows */ /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ /* get certHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); } /* get the first session data */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, &certHmacKey, tpm_state, certAuthHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, certKey, certKeyUsageAuth, /* OIAP */ certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ } /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key pointed to by certHandle, return TPM_AUTHFAIL on error */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_Authdata_Check(tpm_state, *certHmacKey, /* HMAC key */ inParamDigest, cert_auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, certAuth); /* Authorization digest for input */ } /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return TPM_AUTHFAIL on error. */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { if (certKey->authDataUsage != TPM_AUTH_NEVER) { printf("TPM_Process_CertifyKey: Error, cert key authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of authorization data */ /* get keyHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); } /* get the second session data */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, &targetHmacKey, tpm_state, keyAuthHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, targetKey, targetKeyUsageAuth, /* OIAP */ targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ } /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key pointed to by keyHandle, return TPM_AUTH2FAIL on error */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_Auth2data_Check(tpm_state, *targetHmacKey, /* HMAC key */ inParamDigest, target_auth_session_data, /* authorization session */ keynonceOdd, /* Nonce generated by system associated with authHandle */ continueKeySession, keyAuth); /* Authorization digest for input */ } /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced by keyHandle, return TPM_AUTHFAIL on error. */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { printf("TPM_Process_CertifyKey: Error, target key authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* 3. If keyHandle -> payload is not TPM_PT_ASYM, return TPM_INVALID_KEYUSAGE. */ if (returnCode == TPM_SUCCESS) { if (targetKey->tpm_store_asymkey->payload != TPM_PT_ASYM) { printf("TPM_Process_CertifyKey: Error, target key invalid payload %02x\n", targetKey->tpm_store_asymkey->payload); returnCode = TPM_INVALID_KEYUSAGE; } } /* 4. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is TPM_KEY_IDENTITY) */ if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { /* a. If keyHandle -> keyflags -> keyInfo -> migratable is TRUE return TPM_MIGRATEFAIL */ if (targetKey->keyFlags & TPM_MIGRATABLE) { printf("TPM_Process_CertifyKey: Error, target key is migratable\n"); returnCode = TPM_MIGRATEFAIL; } } /* 5. Validate that certHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, if not return TPM_INVALID_KEYUSAGE */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: certHandle -> keyUsage %04hx\n", certKey->keyUsage); if ((certKey->keyUsage != TPM_KEY_SIGNING) && ((certKey->keyUsage) != TPM_KEY_IDENTITY) && ((certKey->keyUsage) != TPM_KEY_LEGACY)) { printf("TPM_Process_CertifyKey: Error, certHandle -> keyUsage %04hx is invalid\n", certKey->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 6. Validate that keyHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); if ((targetKey->keyUsage != TPM_KEY_SIGNING) && ((targetKey->keyUsage) != TPM_KEY_STORAGE) && ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && ((targetKey->keyUsage) != TPM_KEY_BIND) && ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { printf("TPM_Process_CertifyKey: Error, keyHandle -> keyUsage %04hx is invalid\n", targetKey->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 7. If keyHandle -> digestAtRelease requires the use of PCRs 16 or higher to calculate or if keyHandle -> localityAtRelease is not 0x1F */ /* get PCR usage 16 and higher */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Key_GetPCRUsage(&pcrUsage, targetKey, 2); } /* get localityAtRelease */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Key_GetLocalityAtRelease(&localityAtRelease, targetKey); } if (returnCode == TPM_SUCCESS) { if (pcrUsage || (localityAtRelease != TPM_LOC_ALL)) { /* a. Set V1 to 1.2 */ v1Version = 2; /* locality or >2 PCR's */ } /* 8. Else */ else { /* a. Set V1 to 1.1 */ v1Version = 1; /* no locality and <= 2 PCR's */ } } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: V1 %d\n", v1Version); /* 9. If keyHandle -> pcrInfoSize is not 0 */ if (targetKey->pcrInfo.size != 0) { printf("TPM_Process_CertifyKey: Setting PCR info from key\n"); /* a. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ /* i. Create a digestAtRelease according to the specified PCR registers and compare to keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ /* ii. If specified validate any locality requests on error TPM_BAD_LOCALITY */ /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ /* b. If V1 is 1.1 */ if (v1Version == 1) { certifyType = 1; /* i. Create C1 a TPM_CERTIFY_INFO structure */ /* NOTE: Done by TPM_CertifyInfo_Init() */ /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ /* NOTE: Done in common _Set() code below */ /* iii. The TPM MUST set c1 -> pcrInfoSize to 44. */ /* iv. The TPM MUST set c1 -> pcrInfo to a TPM_PCR_INFO structure properly filled out using the information from keyHandle. */ /* This function actually creates the cache, which is serialized later */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_PCRInfo_CreateFromKey(&(certifyInfo.tpm_pcr_info), targetKey); } /* v. The TPM MUST set c1 -> digestAtCreation to 20 bytes of 0x00. */ if (returnCode == TPM_SUCCESS) { TPM_Digest_Init(certifyInfo.tpm_pcr_info->digestAtCreation); } } /* c. Else */ else { certifyType = 2; /* i. Create C1 a TPM_CERTIFY_INFO2 structure */ /* NOTE: Done by TPM_CertifyInfo2_Init() */ /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ /* NOTE: Done in common _Set() code below */ /* iii. Set C1 -> pcrInfoSize to the size of an appropriate TPM_PCR_INFO_SHORT structure. */ /* iv. Set C1 -> pcrInfo to a properly filled out TPM_PCR_INFO_SHORT structure, using the information from keyHandle. */ /* This function actually creates the cache, which is serialized later */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), targetKey); } /* v. Set C1 -> migrationAuthoritySize to 0 */ /* NOTE: Done by TPM_CertifyInfo2_Init() */ } } /* 10. Else */ else { certifyType = 1; /* a. Create C1 a TPM_CERTIFY_INFO structure */ /* NOTE: Done by TPM_CertifyInfo_Init() */ /* b. Fill in C1 with the information from the key pointed to be keyHandle */ /* NOTE: Done in common _Set() code below */ /* c. The TPM MUST set c1 -> pcrInfoSize to 0 */ /* NOTE: Done by TPM_CertifyInfo_Init() */ } } /* 11. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that is the actual public modulus, and does not include any structure formatting. */ /* 12. Set C1 -> pubKeyDigest to H1 */ /* NOTE: Done by TPM_CertifyInfo_Set() or TPM_CertifyInfo2_Set() */ /* 13. The TPM copies the antiReplay parameter to c1 -> data. */ /* Set C1 -> parentPCRStatus to the value from keyHandle NOTE: Implied in specification */ /* Fill in C1 with the information from the key pointed to by keyHandle */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: Setting certifyInfo from target key\n"); if (certifyType == 1) { TPM_Digest_Copy(certifyInfo.data, antiReplay); certifyInfo.parentPCRStatus = targetPCRStatus; returnCode = TPM_CertifyInfo_Set(&certifyInfo, targetKey); } else { TPM_Digest_Copy(certifyInfo2.data, antiReplay); certifyInfo2.parentPCRStatus = targetPCRStatus; returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); } } /* 14. The TPM sets certifyInfo to C1. */ /* NOTE Created as certifyInfo or certifyInfo2 */ /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: Digesting certifyInfo\n"); if (certifyType == 1) { returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo, (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store); } else { returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); } } /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob is returned in outData. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey: Signing certifyInfo digest with certifying key\n"); returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ m1Digest, /* message */ TPM_DIGEST_SIZE, /* message size */ certKey); /* input, signing key */ } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_CertifyKey: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* Return certifyInfo */ if (certifyType == 1) { returnCode = TPM_CertifyInfo_Store(response, &certifyInfo); } else { returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); } } if (returnCode == TPM_SUCCESS) { /* Return outData */ returnCode = TPM_SizedBuffer_Store(response, &outData); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* calculate and set the below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *certHmacKey, /* HMAC key */ cert_auth_session_data, outParamDigest, nonceOdd, continueAuthSession); } /* calculate and set the below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *targetHmacKey, /* HMAC key */ target_auth_session_data, outParamDigest, keynonceOdd, continueKeySession); } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* if there was an error, or continueAuthSession is FALSE, terminate the session */ if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueKeySession) && keyAuthHandleValid) { TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); } if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueAuthSession) && certAuthHandleValid) { TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); } /* cleanup */ TPM_CertifyInfo_Delete(&certifyInfo); /* @1 */ TPM_CertifyInfo2_Delete(&certifyInfo2); /* @2 */ TPM_SizedBuffer_Delete(&outData); /* @3 */ return rcf; } /* 13.9 TPM_CertifyKey2 rev 107 This command is based on TPM_CertifyKey, but includes the ability to certify a Certifiable Migration Key (CMK), which requires extra input parameters. TPM_CertifyKey2 always produces a TPM_CERTIFY_INFO2 structure. TPM_CertifyKey2 does not support the case where (a) the key-to-be-certified requires a usage authorization to be provided but (b) the certifying key does not. If a command tag (in the parameter array) specifies only one authorisation session, then the TPM convention is that the first session listed is ignored (authDataUsage must be TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER for this key) and the incoming session data is used for the second auth session in the list. In TPM_CertifyKey2, the first session is the key to be certified and the second session is the certifying key. */ TPM_RESULT TPM_Process_CertifyKey2(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ TPM_KEY_HANDLE certHandle; /* Handle of the key to be used to certify the key. */ TPM_DIGEST migrationPubDigest; /* The digest of a TPM_MSA_COMPOSITE structure, containing at least one public key of a Migration Authority */ TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce provided to prevent replay-attacks) */ TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be signed. */ TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle */ TPM_BOOL continueKeySession; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key to be signed. HMAC key: key.usageAuth. */ TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle */ TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA certAuth; /* Authorization HMAC key: certKey.auth. */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ TPM_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ TPM_BOOL certAuthHandleValid = FALSE; TPM_BOOL keyAuthHandleValid = FALSE; TPM_SECRET *certHmacKey; TPM_SECRET *targetHmacKey; TPM_BOOL certPCRStatus; TPM_BOOL targetPCRStatus; TPM_KEY *certKey = NULL; /* the key specified by certHandle */ TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ TPM_SECRET *certKeyUsageAuth; TPM_SECRET *targetKeyUsageAuth; TPM_STORE_ASYMKEY *targetStoreAsymkey; TPM_CMK_MIGAUTH m2CmkMigauth; TPM_BOOL hmacValid; TPM_DIGEST migrationAuthority; TPM_DIGEST m1Digest; /* digest of certifyInfo */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_CERTIFY_INFO2 certifyInfo2; /* TPM_CERTIFY_INFO2 relative to keyHandle */ TPM_SIZED_BUFFER outData; /* The signed public key. */ printf("TPM_Process_CertifyKey2: Ordinal Entry\n"); TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @1 */ TPM_SizedBuffer_Init(&outData); /* freed @2 */ TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @3 */ /* get inputs */ /* get keyHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); } /* get certHandle parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: keyHandle %08x\n", keyHandle); returnCode = TPM_Load32(&certHandle, &command, ¶mSize); } /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get antiReplay parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: certHandle %08x\n", certHandle); /* get the migrationPubDigest parameter */ returnCode = TPM_Digest_Load(migrationPubDigest, &command, ¶mSize); } /* get the antiReplay parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag210(tag); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthParams_Get(&keyAuthHandle, &keyAuthHandleValid, keynonceOdd, &continueKeySession, keyAuth, &command, ¶mSize); } if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { printf("TPM_Process_CertifyKey2: keyAuthHandle %08x\n", keyAuthHandle); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_AuthParams_Get(&certAuthHandle, &certAuthHandleValid, nonceOdd, &continueAuthSession, certAuth, &command, ¶mSize); } if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { printf("TPM_Process_CertifyKey2: certAuthHandle %08x\n", certAuthHandle); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_CertifyKey2: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* do not terminate sessions if the command did not parse correctly */ if (returnCode != TPM_SUCCESS) { certAuthHandleValid = FALSE; keyAuthHandleValid = FALSE; } /* Processing */ /* get the keys corresponding to the certHandle and keyHandle parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, FALSE, /* not read-only */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, FALSE, /* not read-only */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } /* get the TPM_STORE_ASYMKEY cache for the target TPM_KEY */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Key_GetStoreAsymkey(&targetStoreAsymkey, targetKey); } /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ if (returnCode == TPM_SUCCESS) { if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { printf("TPM_Process_CertifyKey2: Error, invalid certKey sigScheme %04hx\n", certKey->algorithmParms.sigScheme); returnCode = TPM_BAD_KEY_PROPERTY; } } /* 2. Verify command and key AuthData values: */ /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ /* i. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key pointed to by keyHandle, return TPM_AUTHFAIL on error */ /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key pointed to by certHandle, return TPM_AUTH2FAIL on error */ /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced by keyHandle, return TPM_AUTHFAIL on error */ /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key pointed to by certHandle, return TPM_AUTHFAIL on error */ /* c. else if tag is TPM_TAG_RQU_COMMAND */ /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced by keyHandle, return TPM_AUTHFAIL on error */ /* ii. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return TPM_AUTHFAIL on error. */ /* NOTE: Simplified the above logic as follows */ /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ /* get keyHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); } /* get the first session data */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, &targetHmacKey, tpm_state, keyAuthHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, targetKey, targetKeyUsageAuth, /* OIAP */ targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ } /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key pointed to by keyHandle, return TPM_AUTHFAIL on error */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_Authdata_Check(tpm_state, *targetHmacKey, /* HMAC key */ inParamDigest, target_auth_session_data, /* authorization session */ keynonceOdd, /* Nonce generated by system associated with authHandle */ continueKeySession, keyAuth); /* Authorization digest for input */ } /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced by keyHandle, return TPM_AUTHFAIL on error. */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { printf("TPM_Process_CertifyKey2: Error, target key authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of authorization data */ /* get certHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); } /* get the second session data */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, &certHmacKey, tpm_state, certAuthHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, certKey, certKeyUsageAuth, /* OIAP */ certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ } /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key pointed to by certHandle, return TPM_AUTH2FAIL on error */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_Auth2data_Check(tpm_state, *certHmacKey, /* HMAC key */ inParamDigest, cert_auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, certAuth); /* Authorization digest for input */ } /* If the command is TPM_TAG_RQU_COMMAND */ /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return TPM_AUTHFAIL on error. */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { if (certKey->authDataUsage != TPM_AUTH_NEVER) { printf("TPM_Process_CertifyKey2: Error, cert key authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* 3. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is TPM_KEY_IDENTITY) */ if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { /* a. If keyHandle -> keyFlags -> migratable is TRUE and [keyHandle -> keyFlags-> migrateAuthority is FALSE or (keyHandle -> payload != TPM_PT_MIGRATE_RESTRICTED and keyHandle -> payload != TPM_PT_MIGRATE_EXTERNAL)] return TPM_MIGRATEFAIL */ if ((targetKey->keyFlags & TPM_MIGRATABLE) && (!(targetKey->keyFlags & TPM_MIGRATEAUTHORITY) || ((targetStoreAsymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && (targetStoreAsymkey->payload != TPM_PT_MIGRATE_EXTERNAL)))) { printf("TPM_Process_CertifyKey2: Error, target key migrate fail\n"); returnCode = TPM_MIGRATEFAIL; } } /* 4. Validate that certHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: certHandle ->keyUsage %04hx\n", certKey->keyUsage); if ((certKey->keyUsage != TPM_KEY_SIGNING) && ((certKey->keyUsage) != TPM_KEY_IDENTITY) && ((certKey->keyUsage) != TPM_KEY_LEGACY)) { printf("TPM_Process_CertifyKey2: Error, keyUsage %04hx is invalid\n", certKey->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 5. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); if ((targetKey->keyUsage != TPM_KEY_SIGNING) && ((targetKey->keyUsage) != TPM_KEY_STORAGE) && ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && ((targetKey->keyUsage) != TPM_KEY_BIND) && ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { printf("TPM_Process_CertifyKey2: Error, keyHandle -> keyUsage %04hx is invalid\n", targetKey->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 6. The TPM SHALL create a c1 a TPM_CERTIFY_INFO2 structure from the key pointed to by keyHandle */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); } /* 7. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that is the actual public modulus, and does not include any structure formatting. */ /* 8. Set C1 -> pubKeyDigest to H1 */ /* NOTE: Done by TPM_CertifyInfo2_Set() */ if (returnCode == TPM_SUCCESS) { /* 9. Copy the antiReplay parameter to c1 -> data */ TPM_Digest_Copy(certifyInfo2.data, antiReplay); /* 10. Copy other keyHandle parameters into C1 */ certifyInfo2.parentPCRStatus = targetPCRStatus; /* 11. If keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_EXTERNAL */ if ((targetStoreAsymkey->payload == TPM_PT_MIGRATE_RESTRICTED) || (targetStoreAsymkey->payload == TPM_PT_MIGRATE_EXTERNAL)) { printf("TPM_Process_CertifyKey2: " "TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); /* a. create thisPubKey, a TPM_PUBKEY structure containing the public key, algorithm and parameters corresponding to keyHandle */ /* NOTE Not required. Digest is created directly below */ /* b. Verify that the migration authorization is valid for this key */ /* i. Create M2 a TPM_CMK_MIGAUTH structure */ /* NOTE Done by TPM_CmkMigauth_Init() */ if (returnCode == TPM_SUCCESS) { /* ii. Set M2 -> msaDigest to migrationPubDigest */ TPM_Digest_Copy(m2CmkMigauth.msaDigest, migrationPubDigest ); /* iii. Set M2 -> pubKeyDigest to SHA-1[thisPubKey] */ returnCode = TPM_Key_GeneratePubkeyDigest(m2CmkMigauth.pubKeyDigest, targetKey); } /* iv. Verify that [keyHandle -> migrationAuth] == HMAC(M2) signed by using tpmProof as the secret and return error TPM_MA_SOURCE on mismatch */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: Check migrationAuth\n"); returnCode = TPM_CmkMigauth_CheckHMAC(&hmacValid, /* result */ targetStoreAsymkey->migrationAuth, /* expect */ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ &m2CmkMigauth); } if (returnCode == TPM_SUCCESS) { if (!hmacValid) { printf("TPM_Process_CertifyKey2: Error, Invalid migrationAuth\n"); returnCode = TPM_MA_SOURCE; } } /* c. Set C1 -> migrationAuthority = SHA-1(migrationPubDigest || keyHandle -> payload) */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: Set migrationAuthority\n"); returnCode = TPM_SHA1(migrationAuthority, TPM_DIGEST_SIZE, migrationPubDigest, sizeof(TPM_PAYLOAD_TYPE), &(targetStoreAsymkey->payload), 0, NULL); } if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Set(&(certifyInfo2.migrationAuthority), TPM_DIGEST_SIZE, migrationAuthority); } /* d. if keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED */ /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_RESTRICTED */ /* e. if keyHandle -> payload == TPM_PT_MIGRATE_EXTERNAL */ /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_EXTERNAL */ /* NOTE: Done by TPM_CertifyInfo2_Set() */ } /* 12. Else */ else { printf("TPM_Process_CertifyKey2: " " Not TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); /* a. set C1 -> migrationAuthority = NULL */ /* b. set C1 -> migrationAuthoritySize = 0 */ /* NOTE: Done by TPM_CertifyInfo2_Init() */ /* c. Set C1 -> payloadType = TPM_PT_ASYM */ certifyInfo2.payloadType = TPM_PT_ASYM; } } if (returnCode == TPM_SUCCESS) { /* 13. If keyHandle -> pcrInfoSize is not 0 */ if (targetKey->pcrInfo.size != 0) { printf("TPM_Process_CertifyKey2: Setting PCR info from key\n"); /* a. The TPM MUST set c1 -> pcrInfoSize to match the pcrInfoSize from the keyHandle key. */ /* b. The TPM MUST set c1 -> pcrInfo to match the pcrInfo from the keyHandle key */ /* This function actually creates the cache, which is serialized later */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), targetKey); } /* c. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ /* i. Create a digestAtRelease according to the specified PCR registers and compare to keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ /* ii. If specified validate any locality requests on error TPM_BAD_LOCALITY */ /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ } /* 14. Else */ /* a. The TPM MUST set c1 -> pcrInfoSize to 0 */ /* NOTE: Done by TPM_CertifyInfo2_Init() */ } /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1 */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: Digesting certifyInfo\n"); returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); } /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob is returned in outData */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifyKey2: Signing certifyInfo digest\n"); returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ m1Digest, /* message */ TPM_DIGEST_SIZE, /* message size */ certKey); /* input, signing key */ } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_CertifyKey2: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* Return certifyInfo */ returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); } if (returnCode == TPM_SUCCESS) { /* Return outData */ returnCode = TPM_SizedBuffer_Store(response, &outData); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* calculate and set the below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *targetHmacKey, /* HMAC key */ target_auth_session_data, outParamDigest, keynonceOdd, continueKeySession); } /* calculate and set the below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *certHmacKey, /* HMAC key */ cert_auth_session_data, outParamDigest, nonceOdd, continueAuthSession); } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* if there was an error, or continueAuthSession is FALSE, terminate the session */ if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueKeySession) && keyAuthHandleValid) { TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); } if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueAuthSession) && certAuthHandleValid) { TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); } /* cleanup */ TPM_CertifyInfo2_Delete(&certifyInfo2); /* @1 */ TPM_SizedBuffer_Delete(&outData); /* @2 */ TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @3 */ return rcf; } /* 28.3 TPM_CertifySelfTest rev 94 CertifySelfTest causes the TPM to perform a full self-test and return an authenticated value if the test passes. If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM and the caller have AuthData. If a caller requires proof for a third party, the signing key must be one whose signature is trusted by the third party. A TPM-identity key may be suitable. Information returned by TPM_CertifySelfTest MUST NOT aid identification of an individual TPM. */ TPM_RESULT TPM_Process_CertifySelfTest(tpm_state_t *tpm_state, TPM_STORE_BUFFER *response, TPM_TAG tag, uint32_t paramSize, TPM_COMMAND_CODE ordinal, unsigned char *command, TPM_TRANSPORT_INTERNAL *transportInternal) { TPM_RESULT rcf = 0; /* fatal error precluding response */ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ /* input parameters */ TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform digital signatures. */ TPM_NONCE antiReplay; /* AntiReplay nonce to prevent replay of messages */ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle authorization */ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the inputs and use of keyHandle. HMAC key: key.usageAuth */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ TPM_BOOL authHandleValid = FALSE; TPM_SECRET *hmacKey; TPM_KEY *sigKey; /* from keyHandle */ TPM_BOOL sigKeyPCRStatus; TPM_SECRET *sigKeyUsageAuth; TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ TPM_DIGEST m2Digest; /* message to sign */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ printf("TPM_Process_CertifySelfTest: Ordinal Entry\n"); TPM_SizedBuffer_Init(&sig); /* freed @1 */ /* get inputs */ /* get keyHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); } /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get the antiReplay parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifySelfTest: keyHandle %08x\n", keyHandle); returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag10(tag); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthParams_Get(&authHandle, &authHandleValid, nonceOdd, &continueAuthSession, privAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_CertifySelfTest: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* do not terminate sessions if the command did not parse correctly */ if (returnCode != TPM_SUCCESS) { authHandleValid = FALSE; } /* Processing */ /* 1. The TPM SHALL perform TPM_SelfTestFull. If the test fails the TPM returns the appropriate error code. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifySelfTest: Running self test\n"); returnCode = TPM_SelfTestFullCmd(tpm_state); } /* 2. After successful completion of the self-test the TPM then validates the authorization to use the key pointed to by keyHandle */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &sigKeyPCRStatus, tpm_state, keyHandle, FALSE, /* not read-only */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ if (sigKey->authDataUsage != TPM_AUTH_NEVER) { printf("TPM_Process_CertifySelfTest: Error, authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* get keyHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&sigKeyUsageAuth, sigKey); } /* get the session data */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, sigKey, sigKeyUsageAuth, /* OIAP */ sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ } /* Validate the command parameters using privAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, privAuth); /* Authorization digest for input */ } /* a. If the key pointed to by keyHandle has a signature scheme that is not TPM_SS_RSASSAPKCS1v15_SHA1, the TPM may either return TPM_BAD_SCHEME or may return TPM_SUCCESS and a vendor specific signature. */ if (returnCode == TPM_SUCCESS) { if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { printf("TPM_Process_CertifySelfTest: Error, invalid sigKey sigScheme %04hx\n", sigKey->algorithmParms.sigScheme); returnCode = TPM_BAD_SCHEME; } } /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or TPM_KEY_IDENTITY. */ if (returnCode == TPM_SUCCESS) { if ((sigKey->keyUsage != TPM_KEY_SIGNING) && (sigKey->keyUsage != TPM_KEY_LEGACY) && (sigKey->keyUsage != TPM_KEY_IDENTITY)) { printf("TPM_Process_CertifySelfTest: Error, Illegal keyUsage %04hx\n", sigKey->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 3. Create t1 the NOT null terminated string of "Test Passed" */ /* 4. The TPM creates m2 the message to sign by concatenating t1 || AntiReplay || ordinal. */ if (returnCode == TPM_SUCCESS) { nOrdinal = htonl(ordinal); returnCode = TPM_SHA1(m2Digest, sizeof("Test Passed") - 1, "Test Passed", TPM_NONCE_SIZE, antiReplay, sizeof(TPM_COMMAND_CODE), &nOrdinal, 0, NULL); } /* 5. The TPM signs the SHA-1 of m2 using the key identified by keyHandle, and returns the signature as sig. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_CertifySelfTest: Signing certifyInfo digest\n"); returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ m2Digest, /* message */ TPM_DIGEST_SIZE, /* message size */ sigKey); /* input, signing key */ } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_CertifySelfTest: Ordinal returnCode %08x %u\n", returnCode, returnCode); rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); } /* success response, append the rest of the parameters. */ if (rcf == 0) { if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* return sig */ returnCode = TPM_SizedBuffer_Store(response, &sig); /* checkpoint the end of the outParam's */ outParamEnd = response->buffer_current - response->buffer; } /* digest the above the line output parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ auditStatus, /* input audit status */ transportEncrypt, tag, returnCode, ordinal, /* command ordinal */ response->buffer + outParamStart, /* start */ outParamEnd - outParamStart); /* length */ } /* calculate and set the below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *hmacKey, /* owner HMAC key */ auth_session_data, outParamDigest, nonceOdd, continueAuthSession); } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, transportEncrypt, inParamDigest, outParamDigest, ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* if there was an error, or continueAuthSession is FALSE, terminate the session */ if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueAuthSession) && authHandleValid) { TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); } /* cleanup */ TPM_SizedBuffer_Delete(&sig); /* @1 */ return rcf; }