mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-29 17:42:41 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1743 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1743 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|   * @brief	Embedded Linux TPM Toolbox 2 (ELTT2)
 | |
|   * @details	eltt2.c implements some basic methods to communicate with the Infineon TPM 2.0 without the TDDL lib.
 | |
|   * @file	eltt2.c
 | |
|   * @copyright  Copyright (c) 2014 - 2017 Infineon Technologies AG ( www.infineon.com ).\n
 | |
|   * All rights reserved.\n
 | |
|   * \n
 | |
|   * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
 | |
|   * conditions are met:\n
 | |
|   * \n
 | |
|   * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 | |
|   * disclaimer.\n
 | |
|   * 2. 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.\n
 | |
|   * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
 | |
|   * derived from this software without specific prior written permission.\n
 | |
|   * \n
 | |
|   * 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 "eltt2.h"
 | |
| 
 | |
| /**
 | |
|   * @brief					Main entry point of the application.
 | |
|   * @details					Handles the command line input and starts the communication with the TPM.
 | |
|   * @param	[in]	argc			Counter for input parameters.
 | |
|   * @param	[in]	**argv			Input parameters.
 | |
|   * @return	One of the listed return codes, the TPM return code or the error code stored in the global errno system variable.
 | |
|   * @retval	EXIT_SUCCESS			In case of success.
 | |
|   * @retval	ERR_BAD_CMD			In case an invalid command line option.
 | |
|   * @retval	value of errno			In case of memory allocation error.
 | |
|   * @retval	tpmtool_transmit		All error codes from tpmtool_transmit.
 | |
|   * @retval	return_error_handling		All error codes from return_error_handling.
 | |
|   * @retval	response_print			All error codes from response_print.
 | |
|   * @retval	create_hash_sequence		All error codes from create_hash_sequence.
 | |
|   * @retval	hexstr_to_bytearray		All error codes from hexstr_to_bytearray.
 | |
|   * @retval	pcr_extend			All error codes from pcr_extend.
 | |
|   * @retval	get_random			All error codes from get_random.
 | |
|   * @retval	pcr_read			All error codes from pcr_read.
 | |
|   * @retval	create_hash			All error codes from create_hash.
 | |
|   * @retval	pcr_reset			All error codes from pcr_reset.
 | |
|   */
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
| 	// ---------- Local declarations ----------
 | |
| 	int ret_val = EXIT_SUCCESS;		// Return value.
 | |
| 	uint8_t *tpm_response_buf = NULL;	// Buffer for TPM response.
 | |
| 	ssize_t tpm_response_buf_size = 0;	// Size of tpm_response_buf.
 | |
| 	int i = 0;				// Command line parsing counter.
 | |
| 	int option = 0;				// Command line option.
 | |
| 	uint8_t *input_bytes = NULL;		// Custom command bytes for transmit in case of command line options -b and -E.
 | |
| 	size_t input_bytes_size = 0;		// Size of input_bytes.
 | |
| 	int no_transmission = 0;		// Flag to skip the transmission call, e.g. in case of command line option -h.
 | |
| 	int tpm_error = 0;			// Flag to indicate whether a TPM response has returned a TPM error code or not.
 | |
| 	hash_algo_enum hash_algo = ALG_NULL;	// Variable to indicate the selected hash algorithm.
 | |
| 
 | |
| 	// ---------- Program flow ----------
 | |
| 	printf("\n");
 | |
| 	do // Begin of DO WHILE(FALSE) for error handling.
 | |
| 	{
 | |
| 		// ---------- Allocate memory for buffer containing TPM response ----------
 | |
| 		tpm_response_buf_size = TPM_RESP_MAX_SIZE;
 | |
| 		tpm_response_buf = malloc(tpm_response_buf_size);
 | |
| 		MALLOC_ERROR_CHECK(tpm_response_buf);
 | |
| 		memset(tpm_response_buf, 0xFF, tpm_response_buf_size);
 | |
| 
 | |
| 		// ---------- Check for command line parameters ----------
 | |
| 		if (1 == argc)
 | |
| 		{
 | |
| 			fprintf(stderr, "ELTT needs an option. Use '-h' for displaying help.\n");
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// ---------- Command line parsing with getopt ----------
 | |
| 		opterr = 0; // Disable getopt error messages in case of unknown parameters; we want to use our own error messages.
 | |
| 
 | |
| 		// Loop through parameters with getopt.
 | |
| 		while (-1 != (option = getopt(argc, argv, "cgvhTa:A:b:d:e:E:G:l:r:R:s:S:t:u:z:")))
 | |
| 		{
 | |
| 			switch (option)
 | |
| 			{
 | |
| 				case 'a': // TPM2_HashSequenceStart SHA-1/256/384
 | |
| 				case 'A': // TPM2_HashSequenceStart SHA-256
 | |
| 					HASH_ALG_PARSER('a', 3);
 | |
| 
 | |
| 					ret_val = create_hash_sequence(optarg, hash_algo, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'b': // Enter your own command bytes
 | |
| 					// Allocate the input buffer for hexstr_to_bytearray and tpmtool_transmit.
 | |
| 					input_bytes_size = strlen(optarg) / HEX_BYTE_STRING_LENGTH + strlen(optarg) % HEX_BYTE_STRING_LENGTH; // 2 characters == 1 byte => size of input command bytes: length of input string / 2.
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0xFF, input_bytes_size);
 | |
| 
 | |
| 					// Convert the command line input to bytes.
 | |
| 					ret_val = hexstr_to_bytearray(optarg, input_bytes, input_bytes_size);
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'c': // TPM_CC_ReadClock
 | |
| 					ret_val = tpmtool_transmit(tpm_cc_readclock, sizeof(tpm_cc_readclock), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'd': // TPM_CC_Shutdown
 | |
| 					if (0 == strcasecmp(optarg, "clear"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm_cc_shutdown_clear, sizeof(tpm_cc_shutdown_clear), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else if (0 == strcasecmp(optarg, "state"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm_cc_shutdown_state, sizeof(tpm_cc_shutdown_state), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 						fprintf(stderr, "Unknown option. Use '-h' for more information.\n");
 | |
| 					}
 | |
| 					break;
 | |
| 
 | |
| 				case 'e': // PCR_Extend SHA-1/256/384
 | |
| 				case 'E': // PCR_Extend SHA-256
 | |
| 					if (4 > argc)
 | |
| 					{
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 						fprintf(stderr, "The command '-%c' needs minimum two arguments. Use '-h' for more information.\n", option);
 | |
| 
 | |
| 						// Set the argument count to the next option for error handling.
 | |
| 						optind += 2;
 | |
| 						break;
 | |
| 					}
 | |
| 
 | |
| 					HASH_ALG_PARSER('e', 4);
 | |
| 
 | |
| 					// Allocate the input buffer for pcr_extend and tpmtool_transmit.
 | |
| 					if (ALG_SHA1 == hash_algo)
 | |
| 					{
 | |
| 						input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA1_DIGEST_SIZE;
 | |
| 					}
 | |
| 					else if (ALG_SHA256 == hash_algo)
 | |
| 					{
 | |
| 						input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA256_DIGEST_SIZE;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA384_DIGEST_SIZE;
 | |
| 					}
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0, input_bytes_size);
 | |
| 
 | |
| 					// Create PCR_Extend TPM request.
 | |
| 					ret_val = pcr_extend(optarg, argv[optind], input_bytes, input_bytes_size, hash_algo);
 | |
| 
 | |
| 					// Set the argument count to the next option for error handling.
 | |
| 					optind++;
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'g': // TPM_CC_GetCapability
 | |
| 					ret_val = tpmtool_transmit(tpm2_getcapability_fixed, sizeof(tpm2_getcapability_fixed), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'v': // TPM_CC_GetCapability
 | |
| 					ret_val = tpmtool_transmit(tpm2_getcapability_var, sizeof(tpm2_getcapability_var), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'G': // TPM_CC_GetRandom
 | |
| 					// Allocate the input buffer for get_random and tpmtool_transmit.
 | |
| 					input_bytes_size = (sizeof(tpm2_getrandom));
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0, input_bytes_size);
 | |
| 
 | |
| 					// Create GetRandom TPM request.
 | |
| 					ret_val = get_random(optarg, input_bytes);
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'h': // Help
 | |
| 					print_help();
 | |
| 
 | |
| 					// Set flag to skip any TPM transmission
 | |
| 					no_transmission = 1;
 | |
| 					break;
 | |
| 
 | |
| 				case 'l': // PCR_Allocate SHA-1/256/384
 | |
| 					HASH_ALG_PARSER('l', -1);
 | |
| 
 | |
| 					// Allocate the input buffer for pcr_read and tpmtool_transmit.
 | |
| 					input_bytes_size = sizeof(tpm2_pcr_allocate);
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0, input_bytes_size);
 | |
| 
 | |
| 					// Create PCR_Allocate TPM request.
 | |
| 					ret_val = pcr_allocate(input_bytes, hash_algo);
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'r': // PCR_Read SHA-1/256/384
 | |
| 				case 'R': // PCR_Read SHA-256
 | |
| 					HASH_ALG_PARSER('r', 3);
 | |
| 
 | |
| 					// Allocate the input buffer for pcr_read and tpmtool_transmit.
 | |
| 					input_bytes_size = sizeof(tpm2_pcr_read);
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0, input_bytes_size);
 | |
| 
 | |
| 					// Create PCR_Read TPM request.
 | |
| 					ret_val = pcr_read(optarg, input_bytes, hash_algo);
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 's': // Hash SHA-1/256/384
 | |
| 				case 'S': // Hash SHA-256
 | |
| 					HASH_ALG_PARSER('s', 3);
 | |
| 
 | |
| 					// Allocate the input buffer for create_hash and tpmtool_transmit.
 | |
| 					input_bytes_size = strlen(optarg) / HEX_BYTE_STRING_LENGTH + strlen(optarg) % HEX_BYTE_STRING_LENGTH + sizeof(tpm2_hash);
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0, input_bytes_size);
 | |
| 
 | |
| 					// Create Hash TPM request.
 | |
| 					ret_val = create_hash(optarg, hash_algo, input_bytes, input_bytes_size);
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 't': // TPM2_SelfTest
 | |
| 					if (0 == strcasecmp(optarg, "not_full"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm2_self_test, sizeof(tpm2_self_test), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else if (0 == strcasecmp(optarg, "full"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm2_self_test_full, sizeof(tpm2_self_test_full), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else if (0 == strcasecmp(optarg, "incremental"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm2_self_test_incremental, sizeof(tpm2_self_test_incremental), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 						fprintf(stderr, "Unknown option. Use '-h' for more information.\n");
 | |
| 					}
 | |
| 					break;
 | |
| 
 | |
| 				case 'T': // TPM_CC_GetTestResult
 | |
| 					ret_val = tpmtool_transmit(tpm_cc_get_test_result, sizeof(tpm_cc_get_test_result), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				case 'u': // TPM2_Startup
 | |
| 					if (0 == strcasecmp(optarg, "clear"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm2_startup_clear, sizeof(tpm2_startup_clear), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else if (0 == strcasecmp(optarg, "state"))
 | |
| 					{
 | |
| 						ret_val = tpmtool_transmit(tpm2_startup_state, sizeof(tpm2_startup_state), tpm_response_buf, &tpm_response_buf_size);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 						fprintf(stderr, "Unknown option. Use '-h' for more information.\n");
 | |
| 					}
 | |
| 					break;
 | |
| 
 | |
| 				case 'z': // PCR_Reset
 | |
| 					// Allocate the input buffer for pcr_reset and tpmtool_transmit
 | |
| 					input_bytes_size = sizeof(tpm2_pcr_reset);
 | |
| 					input_bytes = malloc(input_bytes_size);
 | |
| 					MALLOC_ERROR_CHECK(input_bytes);
 | |
| 					memset(input_bytes, 0, input_bytes_size);
 | |
| 
 | |
| 					// Create PCR_Reset TPM request.
 | |
| 					ret_val = pcr_reset(optarg, input_bytes);
 | |
| 					RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 					// Send bytes to TPM.
 | |
| 					ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size);
 | |
| 					break;
 | |
| 
 | |
| 				default:
 | |
| 					if ('a' == optopt || 'A' == optopt || 'b' == optopt || 'e' == optopt || 'E' == optopt || 'G' == optopt ||
 | |
| 						'l' == optopt || 'r' == optopt || 'R' == optopt || 's' == optopt || 'S' == optopt || 'z' == optopt)
 | |
| 					{
 | |
| 						// Error output if arguments are missing.
 | |
| 						fprintf(stderr, "Option '-%c' requires additional arguments. Use '-h' for more information.\n", optopt);
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 					}
 | |
| 					else if ('d' == optopt)
 | |
| 					{
 | |
| 						// TPM shutdown default option without parameter (default is tpm_cc_shutdown_clear).
 | |
| 						ret_val = tpmtool_transmit(tpm_cc_shutdown_clear, sizeof(tpm_cc_shutdown_clear), tpm_response_buf, &tpm_response_buf_size);
 | |
| 						option='d'; // for response_print handler
 | |
| 					}
 | |
| 					else if ('t' == optopt)
 | |
| 					{
 | |
| 						// TPM shutdown default option without parameter (default is tpm2_self_test).
 | |
| 						ret_val = tpmtool_transmit(tpm2_self_test, sizeof(tpm2_self_test), tpm_response_buf, &tpm_response_buf_size);
 | |
| 						option='t'; // for response_print handler
 | |
| 					}
 | |
| 					else if ('u' == optopt)
 | |
| 					{
 | |
| 						// TPM startup default option without parameter (default is tpm2_startup_clear).
 | |
| 						ret_val = tpmtool_transmit(tpm2_startup_clear, sizeof(tpm2_startup_clear), tpm_response_buf, &tpm_response_buf_size);
 | |
| 						option='u'; // for response_print handler
 | |
| 					}
 | |
| 					else if (isprint(optopt))
 | |
| 					{
 | |
| 						// Unknown parameter.
 | |
| 						fprintf(stderr, "Unknown option '-%c'. Use '-h' for more information.\n", optopt);
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						// Non-printable character.
 | |
| 						fprintf(stderr, "Invalid command line character. Use '-h' for more information.\n");
 | |
| 						ret_val = ERR_BAD_CMD;
 | |
| 					}
 | |
| 					break;
 | |
| 			} // End of switch.
 | |
| 
 | |
| 			// ---------- Output and error handling ----------
 | |
| 			// Check for transmission errors or skipped transmission.
 | |
| 			if (EXIT_SUCCESS != ret_val || 1 == no_transmission)
 | |
| 			{
 | |
| 				// Exit command line parameter parsing loop.
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			// Transmission has been successful, now get TPM return code from TPM response.
 | |
| 			ret_val = return_error_handling(tpm_response_buf);
 | |
| 			if (EXIT_SUCCESS != ret_val) // Check for errors
 | |
| 			{
 | |
| 				// Set flag to indicate a TPM error.
 | |
| 				tpm_error = 1;
 | |
| 
 | |
| 				// Go out of command line parameter parsing loop.
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			// Print TPM response
 | |
| 			ret_val = response_print(tpm_response_buf, tpm_response_buf_size, option);
 | |
| 			RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 			// Free memory for next command line option
 | |
| 			MEMSET_FREE(input_bytes, input_bytes_size);
 | |
| 		} // End of while (command line parameter parsing loop).
 | |
| 
 | |
| 		// If no error has occurred so far, handle remaining unknown parameters, if present.
 | |
| 		RET_VAL_CHECK(ret_val); // If we do not check and break here in case of an error, we would override the previous error
 | |
| 		for (i = optind; i < argc; i++)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Non-option argument '%s'. Use '-h' for more information.\n", argv[i]);
 | |
| 		}
 | |
| 	} while (0); // End of DO WHILE FALSE loop.
 | |
| 
 | |
| 	// Check for non-TPM error.
 | |
| 	if (EXIT_SUCCESS != ret_val && 1 != tpm_error)
 | |
| 	{
 | |
| 		fprintf(stderr, "Unexpected error: 0x%08X\n", ret_val);
 | |
| 	}
 | |
| 
 | |
| 	// Map TPM return value 0x100 (TPM_RC_INITIALIZE) to 0x101 (TPM_RC_FAILURE), since in case you
 | |
| 	// run ELTT 2 in a python script only the lowest byte of the return code is actually being returned.
 | |
| 	// But since the lowest byte of 0x100 is 0x00 (== TPM_RC_SUCCESS), python would not be able to
 | |
| 	// distinguish between 0x000 and 0x100 as return code, therefore we need the mapping.
 | |
| 	if (TPM_RC_INITIALIZE == ret_val)
 | |
| 	{
 | |
| 		ret_val = TPM_RC_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	// ---------- Cleanup ----------
 | |
| 	MEMSET_FREE(tpm_response_buf, tpm_response_buf_size);
 | |
| 	MEMSET_FREE(input_bytes, input_bytes_size);
 | |
| 
 | |
| 	printf("\n");
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| int tpmtool_transmit(const uint8_t *buf, ssize_t length, uint8_t *response, ssize_t *resp_length)
 | |
| {
 | |
| 	// ---------- Transmit command given in buf to device with handle given in dev_tpm ----------
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	int dev_tpm = -1;		// TPM device handle.
 | |
| 	ssize_t transmit_size = 0;	// Amount of bytes sent to / received from the TPM.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		// Check input parameters.
 | |
| 		NULL_POINTER_CHECK(buf);
 | |
| 		NULL_POINTER_CHECK(response);
 | |
| 		NULL_POINTER_CHECK(resp_length);
 | |
| 
 | |
| 		if (0 >= length)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'length' must be larger than 0.");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (TPM_REQ_MAX_SIZE < length)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'length' must be smaller than or equal to %u.", TPM_REQ_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (TPM_CMD_HEADER_SIZE >= *resp_length)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter '*resp_length' must be at least %u.", TPM_CMD_HEADER_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (TPM_RESP_MAX_SIZE < *resp_length)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter '*resp_length' must be smaller than or equal to %u.", TPM_RESP_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		memset(response, 0, *resp_length);
 | |
| 
 | |
| 		// ---------- Open TPM device ----------
 | |
| 		dev_tpm = open("/dev/tpm0", O_RDWR);
 | |
| 		if (-1 == dev_tpm)
 | |
| 		{
 | |
| 			ret_val = errno;
 | |
| 			fprintf(stderr, "Error opening the device.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Send request data to TPM.
 | |
| 		transmit_size = write(dev_tpm, buf, length);
 | |
| 		if (transmit_size == ERR_COMMUNICATION || length != transmit_size)
 | |
| 		{
 | |
| 			ret_val = errno;
 | |
| 			fprintf(stderr, "Error sending request to TPM.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Read the TPM response header.
 | |
| 		transmit_size = read(dev_tpm, response, TPM_RESP_MAX_SIZE);
 | |
| 		if (transmit_size == ERR_COMMUNICATION)
 | |
| 		{
 | |
| 			ret_val = errno;
 | |
| 			fprintf(stderr, "Error reading response from TPM.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Update response buffer length with value of data length returned by TPM.
 | |
| 		*resp_length = transmit_size;
 | |
| 	} while (0);
 | |
| 
 | |
| 	// ---------- Close TPM device ----------
 | |
| 	if (-1 != dev_tpm)
 | |
| 	{
 | |
| 		// Close file handle.
 | |
| 		close(dev_tpm);
 | |
| 
 | |
| 		// Invalidate file handle.
 | |
| 		dev_tpm = -1;
 | |
| 	}
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int return_error_handling(uint8_t *response_buf)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint64_t tpm_rc = 0;		// Return code from TPM header.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(response_buf);
 | |
| 
 | |
| 		ret_val = buf_to_uint64(response_buf, 6, sizeof(uint32_t), &tpm_rc, TPM_RESP_MAX_SIZE); // TPM Return code type is 32 bit unsigned int!
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		// Assign TPM return code to ret_val.
 | |
| 		ret_val = tpm_rc;
 | |
| 
 | |
| 		if (TPM_RC_SUCCESS != tpm_rc)
 | |
| 		{
 | |
| 			fprintf(stderr, "TPM Error 0x%.8" PRIx64 ": ", tpm_rc);
 | |
| 		}
 | |
| 
 | |
| 		// Handle some known TPM return codes.
 | |
| 		switch (tpm_rc)
 | |
| 		{
 | |
| 			case TPM_RC_SUCCESS: // 0x00
 | |
| 				break;
 | |
| 
 | |
| 			case TPM_RC_BAD_TAG: // 0x1E
 | |
| 				fprintf(stderr, "The tag value sent to for a command is invalid.\n");
 | |
| 				break;
 | |
| 
 | |
| 			case TPM_RC_SIZE: // 0x95
 | |
| 				fprintf(stderr, "Structure is the wrong size.\n");
 | |
| 				break;
 | |
| 
 | |
| 			case TPM_RC_INITIALIZE: // 0x100
 | |
| 				fprintf(stderr, "TPM not initialized.\n");
 | |
| 				break;
 | |
| 
 | |
| 			case TPM_RC_LOCALITY: // 0x907
 | |
| 				fprintf(stderr, "Bad locality.\n");
 | |
| 				break;
 | |
| 
 | |
| 			default:
 | |
| 				fprintf(stderr, "See TPM Library Specification for more information.\n");
 | |
| 				break;
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int response_print(uint8_t *response_buf, size_t resp_size, int option)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(response_buf);
 | |
| 
 | |
| 		if (0 >= resp_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be larger than 0.");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (TPM_RESP_MAX_SIZE < resp_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be smaller than or equal to %u.\n", TPM_RESP_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		switch (option)
 | |
| 		{
 | |
| 			case 'a':
 | |
| 			case 'A': // Print the returned hash number.
 | |
| 				ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_HASH_WITHOUT_HEADER, PRINT_RESPONSE_HASH);
 | |
| 				break;
 | |
| 			case 'b': // Print the response value in hex.
 | |
| 			case 'e':
 | |
| 			case 'E': // Print the PCR extend response.
 | |
| 				ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS);
 | |
| 				break;
 | |
| 
 | |
| 			case 'c': // Print the TPM clock values.
 | |
| 				ret_val = print_clock_info(response_buf);
 | |
| 				break;
 | |
| 
 | |
| 			case 'd': // Print "Shutdown works as expected."
 | |
| 				printf("Shutdown works as expected.\n");
 | |
| 				break;
 | |
| 
 | |
| 			case 'g': // Print the fixed capability flags.
 | |
| 				ret_val = print_capability_flags(response_buf, PT_FIXED_SELECTOR);
 | |
| 				break;
 | |
| 
 | |
| 			case 'v': // Print the variable capability flags.
 | |
| 				ret_val = print_capability_flags(response_buf, PT_VAR_SELECTOR);
 | |
| 				break;
 | |
| 
 | |
| 			case 'G': // Print the returned random value in hex.
 | |
| 				printf("Random value:\n");
 | |
| 				ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITHOUT_HEADER, PRINT_RESPONSE_HEX_BLOCK);
 | |
| 				break;
 | |
| 
 | |
| 			case 'r':
 | |
| 			case 'R': // Print the response value in hex.
 | |
| 				ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_PCR_WITHOUT_HEADER, PRINT_RESPONSE_CLEAR);
 | |
| 				break;
 | |
| 
 | |
| 			case 's':
 | |
| 			case 'S': // Print the returned hash number.
 | |
| 				ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITHOUT_HEADER, PRINT_RESPONSE_HASH);
 | |
| 				break;
 | |
| 
 | |
| 			case 't': // Print "Successfully tested. Works as expected."
 | |
| 				printf("Successfully tested. Works as expected.\n");
 | |
| 				break;
 | |
| 
 | |
| 			case 'T': // Print response value hex without the header.
 | |
| 				printf("Test Result:               ");
 | |
| 				ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITHOUT_HEADER, PRINT_RESPONSE_CLEAR);
 | |
| 				break;
 | |
| 
 | |
| 			case 'u': // Print "Startup works as expected."
 | |
| 				printf("Startup works as expected.\n");
 | |
| 				break;
 | |
| 
 | |
| 			default: // Print "Done."
 | |
| 				printf("Done.\n");
 | |
| 				break;
 | |
| 		}
 | |
| 		printf("\n");
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int print_response_buf(uint8_t *response_buf, size_t resp_size, uint32_t offset, int format)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint32_t i = 0;			// Loop variable.
 | |
| 	uint64_t data_size = 0;		// Size of response data.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(response_buf);
 | |
| 
 | |
| 		if (0 >= resp_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be larger than 0.");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (TPM_RESP_MAX_SIZE < resp_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be smaller than or equal to %u.\n", TPM_RESP_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (resp_size <= offset)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Offset %u cannot be equal or larger than input buffer size %zu.\n", offset, resp_size);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		switch (format)
 | |
| 		{
 | |
| 			case PRINT_RESPONSE_CLEAR:
 | |
| 				for (i = 0; i < resp_size - offset; i++)
 | |
| 				{
 | |
| 					printf("%02X ", response_buf[i + offset]);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case PRINT_RESPONSE_HEADERBLOCKS:
 | |
| 				if (TPM_CMD_HEADER_SIZE > resp_size)
 | |
| 				{
 | |
| 					ret_val = EINVAL;
 | |
| 					fprintf(stderr, "Response size is too small.\n");
 | |
| 					break;
 | |
| 				}
 | |
| 
 | |
| 				printf("TPM Response:\n");
 | |
| 				for (i = 0; i < resp_size - offset; i++)
 | |
| 				{
 | |
| 					printf("%02X ", response_buf[i + offset]);
 | |
| 					if (i == 1) // Bytes 0 and 1 are TPM TAG.
 | |
| 					{
 | |
| 						printf("                        TPM TAG\n");
 | |
| 					}
 | |
| 					else if (i == 5) // Bytes 2 to 5 are the response length.
 | |
| 					{
 | |
| 						printf("                  RESPONSE SIZE\n");
 | |
| 					}
 | |
| 					else if (i == 9) // Last 4 bytes in header are the TPM return code.
 | |
| 					{
 | |
| 						printf("                  RETURN CODE\n");
 | |
| 						if (i + 1 < resp_size - offset)
 | |
| 						{
 | |
| 							printf(" Command-specific response Data:\n");
 | |
| 						}
 | |
| 					}
 | |
| 					else if (i >= TPM_CMD_HEADER_SIZE && (i+1) % 10 == 0) // After all header bytes have been printed, start new line after every 10 bytes of data.
 | |
| 					{
 | |
| 						printf("\n");
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case PRINT_RESPONSE_HEX_BLOCK:
 | |
| 				for (i = 0; i < resp_size - offset; i++)
 | |
| 				{
 | |
| 					if (i % 16 == 0)
 | |
| 					{
 | |
| 						printf("\n0x%08X:   ", i);
 | |
| 					}
 | |
| 					printf("0x%02X  ", response_buf[i + offset]);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case PRINT_RESPONSE_HASH:
 | |
| 				ret_val = buf_to_uint64(response_buf, offset - sizeof(uint16_t), sizeof(uint16_t), &data_size, resp_size); // Data size actually is only an uint16_t and should always be stored right before the actual data
 | |
| 				if (data_size > resp_size - offset)
 | |
| 				{
 | |
| 					ret_val = EINVAL;
 | |
| 					fprintf(stderr, "Invalid response data size.\n");
 | |
| 					break;
 | |
| 				}
 | |
| 				for (i = 0; i < data_size; i++)
 | |
| 				{
 | |
| 					if (i % 8 == 0)
 | |
| 					{
 | |
| 						printf("\n0x%08X:   ", i);
 | |
| 					}
 | |
| 					printf("%02X  ", response_buf[i + offset]);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			default:
 | |
| 				ret_val = EINVAL;
 | |
| 				fprintf(stderr, "Unknown output format.\n");
 | |
| 				break;
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static void print_help()
 | |
| {
 | |
| 	printf("'-a [hash algorithm] <data bytes>': Hash Sequence SHA-1/256/384 [default: SHA-1]\n");
 | |
| 	printf("        -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n");
 | |
| 	printf("           Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-A <data bytes>': Hash Sequence SHA-256\n");
 | |
| 	printf("        -> Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-b <command bytes>': Enter your own TPM command\n");
 | |
| 	printf("        -> Command bytes: Enter your command bytes in hex like '0f56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-c': Read Clock\n");
 | |
| 	printf("'-d <shutdown type>': Shutdown\n");
 | |
| 	printf("        -> Shutdown types: clear [default], state\n");
 | |
| 	printf("'-e [hash algorithm] <PCR index> <PCR digest>': PCR Extend SHA-1/256/384 [default: SHA-1]\n");
 | |
| 	printf("        -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n");
 | |
| 	printf("           PCR index:  Enter the PCR index in hex like '17' for 0x17\n");
 | |
| 	printf("           PCR digest: Enter the value to extend the PCR with in hex like '0f56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-E <PCR index> <PCR digest>': PCR Extend SHA-256\n");
 | |
| 	printf("        -> PCR index:  Enter the PCR index in hex like '17' for 0x17\n");
 | |
| 	printf("           PCR digest: Enter the value to extend the PCR with in hex like '0f56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-g': Get fixed capability values\n");
 | |
| 	printf("'-v': Get variable capability values\n");
 | |
| 	printf("'-G <byte count>': Get Random\n");
 | |
| 	printf("        -> Enter desired number of random bytes in hex like '20' for 0x20 (=32 bytes, maximum)\n");
 | |
| 	printf("'-h': Help\n");
 | |
| 	printf("'-l <hash algorithm>': PCR allocate SHA-1/256/384\n");
 | |
| 	printf("        -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n");
 | |
| 	printf("'-r [hash algorithm] <PCR index>': PCR Read SHA-1/256/384 [default: SHA-1]\n");
 | |
| 	printf("        -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n");
 | |
| 	printf("           PCR index: Enter PCR number in hex like '17' for 0x17\n");
 | |
| 	printf("'-R <PCR index>': PCR Read SHA-256\n");
 | |
| 	printf("        -> PCR index: Enter PCR number in hex like '17' for 0x17\n");
 | |
| 	printf("'-s [hash algorithm] <data bytes>': Hash SHA-1/256/384 [default: SHA-1]\n");
 | |
| 	printf("        -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n");
 | |
| 	printf("           Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-S <data bytes>': Hash SHA-256\n");
 | |
| 	printf("        -> Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n");
 | |
| 	printf("'-t <selftest type>': SelfTest\n");
 | |
| 	printf("        -> Selftest type: not_full [default], full, incremental\n");
 | |
| 	printf("'-T': Get Test Result\n");
 | |
| 	printf("'-u <startup type>': Startup\n");
 | |
| 	printf("        -> Startup types: clear [default], state\n");
 | |
| 	printf("'-z <PCR index>': PCR Reset SHA-1, SHA-256, and SHA-384\n");
 | |
| 	printf("        -> PCR index: Enter PCR number in hex like '17' for 0x17\n");
 | |
| }
 | |
| 
 | |
| static int print_capability_flags(uint8_t *response_buf, uint8_t cap_selector)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint64_t propertyValue = 0;	// Value of the read property.
 | |
| 	uint64_t propertyKey = 0;	// Key of the property.
 | |
| 	int tmp = 0;			// Temporary buffer.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(response_buf);
 | |
| 		if(cap_selector == PT_FIXED_SELECTOR)
 | |
| 		{
 | |
| 			printf("\nTPM capability information of fixed properties:\n");
 | |
| 			printf("=========================================================\n");
 | |
| 
 | |
| 			for(int x = 0x13; x<(TPM_RESP_MAX_SIZE-8); x+=8)
 | |
| 			{	//Iterate over each property key/value pair
 | |
| 				ret_val = buf_to_uint64(response_buf, x, 4, &propertyKey, TPM_RESP_MAX_SIZE);
 | |
| 				RET_VAL_CHECK(ret_val);
 | |
| 				ret_val = buf_to_uint64(response_buf, x+4, 4, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 				RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 				switch(propertyKey)
 | |
| 				{
 | |
| 					case 0x100:
 | |
| 						printf("TPM_PT_FAMILY_INDICATOR:        %c%c%c%c\n", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]);
 | |
| 						break;
 | |
| 					case 0x100+1:
 | |
| 						printf("TPM_PT_LEVEL:                   %" PRIu64 "\n", propertyValue);
 | |
| 						break;
 | |
| 					case 0x100+2:
 | |
| 						printf("TPM_PT_REVISION:                %" PRIu64 "\n", propertyValue);
 | |
| 						break;
 | |
| 					case 0x100+3:
 | |
| 						printf("TPM_PT_DAY_OF_YEAR:             %" PRIu64 "\n", propertyValue);
 | |
| 						break;
 | |
| 					case 0x100+4:
 | |
| 						printf("TPM_PT_YEAR:                    %" PRIu64 "\n", propertyValue);
 | |
| 						break;
 | |
| 					case 0x100+5:
 | |
| 						printf("TPM_PT_MANUFACTURER:            %c%c%c%c\n", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]);
 | |
| 						break;
 | |
| 					case 0x100+6:
 | |
| 						printf("TPM_PT_VENDOR_STRING:           ");
 | |
| 						printf("%c%c%c%c",  response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]);
 | |
| 						break;
 | |
| 					case 0x100+7: // it is assumed that TPM_PT_VENDOR_STRING_2 follows _1
 | |
| 						printf("%c%c%c%c",  response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]);
 | |
| 						break;
 | |
| 					case 0x100+8:
 | |
| 						printf("%c%c%c%c",  response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]);
 | |
| 						break;
 | |
| 					case 0x100+9:
 | |
| 						printf("%c%c%c%c\n",  response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]);
 | |
| 						break;
 | |
| 					case 0x100+10:
 | |
| 						printf("TPM_PT_VENDOR_TPM_TYPE:         %" PRIu64 "\n", propertyValue);
 | |
| 						break;
 | |
| 					case 0x100+11:
 | |
| 						// special handling for firmware version XX.xx.xxxx.x
 | |
| 						ret_val = buf_to_uint64(response_buf, x+4, 2, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 						RET_VAL_CHECK(ret_val);
 | |
| 						printf("TPM_PT_FIRMWARE_VERSION:        %" PRIu64 "", propertyValue);
 | |
| 
 | |
| 						ret_val = buf_to_uint64(response_buf, x+6, 2, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 						RET_VAL_CHECK(ret_val);
 | |
| 						printf(".%" PRIu64 "", propertyValue);
 | |
| 						break;
 | |
| 					case 0x100+12:
 | |
| 						// special handling for firmware version XX.xx.xxxx.x
 | |
| 						ret_val = buf_to_uint64(response_buf, x+4, 2, &propertyValue, TPM_RESP_MAX_SIZE); // Check for output version.
 | |
| 						RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 						if (2 <= propertyValue) // Infineon custom format
 | |
| 						{
 | |
| 							ret_val = buf_to_uint64(response_buf, x+5, 2, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 							RET_VAL_CHECK(ret_val);
 | |
| 							printf(".%" PRIu64 "", propertyValue);
 | |
| 
 | |
| 							ret_val = buf_to_uint64(response_buf, x+7, 1, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 							RET_VAL_CHECK(ret_val);
 | |
| 							printf(".%" PRIu64 "\n", propertyValue);
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							ret_val = buf_to_uint64(response_buf, x+4, 4, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 							RET_VAL_CHECK(ret_val);
 | |
| 							printf(".%" PRIu64 "\n", propertyValue);
 | |
| 						}
 | |
| 						break;
 | |
| 
 | |
| 					case 0x100+24:
 | |
| 						printf("\nTPM_PT_MEMORY:\n");
 | |
| 						printf("=========================================================\n");
 | |
| 						tmp = ((propertyValue & (1<<0)) == 0? 0:1); // Check bit 0 value.
 | |
| 						printf("Shared RAM:                     %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<1)) == 0? 0:1); // Check bit 1 value.
 | |
| 						printf("Shared NV:                      %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<2)) == 0? 0:1); // Check bit 2 value.
 | |
| 						printf("Object Copied To Ram:           %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 						//bit 31:3 = reserved
 | |
| 						break;
 | |
| 
 | |
| 					case 0x200:
 | |
| 						printf("\nTPM_PT_PERMANENT:\n");
 | |
| 						printf("=========================================================\n");
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<0)) == 0? 0:1); // Check bit 0 value.
 | |
| 						printf("Owner Auth Set:                 %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<1)) == 0? 0:1); // Check bit 1 value.
 | |
| 						printf("Sendorsement Auth Set:          %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<2)) == 0? 0:1); // Check bit 2 value.
 | |
| 						printf("Lockout Auth Set:               %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						//bit 7:3 = reserved
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<8)) == 0? 0:1); // Check bit 8 value.
 | |
| 						printf("Disable Clear:                  %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<9)) == 0? 0:1); // Check bit 9 value.
 | |
| 						printf("In Lockout:                     %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<10)) == 0? 0:1); // Check bit 10 value.
 | |
| 						printf("TPM Generated EPS:              %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 						//bit 31:11 = reserved
 | |
| 						break;
 | |
| 					default:
 | |
| 						// Unknown attribute - ignore
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		else if (cap_selector == PT_VAR_SELECTOR)
 | |
| 		{
 | |
| 			NULL_POINTER_CHECK(response_buf);
 | |
| 
 | |
| 			printf("\nTPM capability information of variable properties:\n");
 | |
| 			for(int x = 0x13; x<TPM_RESP_MAX_SIZE-8; x+=8)
 | |
| 			{	//Iterate over each property key/value pair
 | |
| 				ret_val = buf_to_uint64(response_buf, x, 4, &propertyKey, TPM_RESP_MAX_SIZE);
 | |
| 				RET_VAL_CHECK(ret_val);
 | |
| 				ret_val = buf_to_uint64(response_buf, x+4, 4, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 				RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 				switch(propertyKey)
 | |
| 				{
 | |
| 					case 0x201:
 | |
| 						printf("\nTPM_PT_STARTUP_CLEAR:\n");
 | |
| 						printf("=========================================================\n");
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<0)) == 0? 0:1); // Check bit 0 value.
 | |
| 						printf("Ph Enable:                      %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<1)) == 0? 0:1); // Check bit 1 value.
 | |
| 						printf("Sh Enable:                      %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 
 | |
| 						tmp = ((propertyValue & (1<<2)) == 0? 0:1); // Check bit 2 value.
 | |
| 						printf("Eh Enable:                      %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 						//bit 30:3 = reserved
 | |
| 						tmp = ((propertyValue & (1U<<31)) == 0? 0:1); // Check bit 31 value.
 | |
| 						printf("Orderly:                        %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n"));
 | |
| 						break;
 | |
| 					default:
 | |
| 						// Unknown attribute - ignore
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int print_clock_info(uint8_t *response_buf)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint64_t propertyValue = 0;	// Value of the read property.
 | |
| 	uint64_t tmp_value = 0;		// Helper variable for calculating actual values.
 | |
| 	uint64_t sec = 0;		// Value for seconds.
 | |
| 	uint64_t tmp = 0;		// buf_to_uint64 return value.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(response_buf);
 | |
| 
 | |
| 		printf("\nClock info:\n");
 | |
| 		printf("=========================================================\n");
 | |
| 
 | |
| 		ret_val = buf_to_uint64(response_buf, TPM_CMD_HEADER_SIZE, 8, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		printf("Time since the last TPM_Init:\n%" PRIu64 " ms  =  ", propertyValue);
 | |
| 
 | |
| 		sec = propertyValue / MILISECOND_TO_SECOND;
 | |
| 		tmp_value = sec / YEAR_SECONDS;
 | |
| 		printf("%" PRIu64 " y, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = (sec % YEAR_SECONDS) / DAY_SECONDS;
 | |
| 		printf("%" PRIu64 " d, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = ((sec % YEAR_SECONDS) % DAY_SECONDS) / HOUR_SECONDS;
 | |
| 		printf("%" PRIu64 " h, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) / MINUTE_SECONDS;
 | |
| 		printf("%" PRIu64 " min, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) % MINUTE_SECONDS;
 | |
| 		printf("%" PRIu64 " s, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = propertyValue % MILISECOND_TO_SECOND;
 | |
| 		printf("%" PRIu64 " ms\n\n", tmp_value);
 | |
| 
 | |
| 		ret_val = buf_to_uint64(response_buf, 18, 8, &propertyValue, TPM_RESP_MAX_SIZE);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		printf("Time during which the TPM has been powered:\n%" PRIu64 " ms  =  ", propertyValue);
 | |
| 
 | |
| 		sec = propertyValue / MILISECOND_TO_SECOND;
 | |
| 		tmp_value = sec / YEAR_SECONDS;
 | |
| 		printf("%" PRIu64 " y, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = (sec % YEAR_SECONDS) / DAY_SECONDS;
 | |
| 		printf("%" PRIu64 " d, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = ((sec % YEAR_SECONDS) % DAY_SECONDS) / HOUR_SECONDS;
 | |
| 		printf("%" PRIu64 " h, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) / MINUTE_SECONDS;
 | |
| 		printf("%" PRIu64 " min, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) % MINUTE_SECONDS;
 | |
| 		printf("%" PRIu64 " s, ", tmp_value);
 | |
| 
 | |
| 		tmp_value = propertyValue % MILISECOND_TO_SECOND;
 | |
| 		printf("%" PRIu64 " ms\n\n", tmp_value);
 | |
| 
 | |
| 		ret_val = buf_to_uint64(response_buf, 26, 4, &tmp, TPM_RESP_MAX_SIZE);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		printf("TPM Reset since the last TPM2_Clear:            %" PRIu64 "\n", tmp);
 | |
| 
 | |
| 		ret_val = buf_to_uint64(response_buf, 30, 4, &tmp, TPM_RESP_MAX_SIZE);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		printf("Number of times that TPM2_Shutdown:             %" PRIu64 "\n", tmp);
 | |
| 
 | |
| 		printf("Safe:                                           %i = %s", response_buf[34], (response_buf[34]? "Yes\n" : "No\n"));
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int buf_to_uint64(uint8_t *input_buffer, uint32_t offset, uint32_t length, uint64_t *output_value, uint32_t input_buffer_size)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint32_t i = 0;			// Loop variable.
 | |
| 	uint64_t tmp = 0;		// Temporary variable for value calculation.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(input_buffer);
 | |
| 		NULL_POINTER_CHECK(output_value);
 | |
| 
 | |
| 		*output_value = 0;
 | |
| 
 | |
| 		if (offset >= input_buffer_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'input_buffer_size' must be larger than %u.\n", offset);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (INT_MAX < input_buffer_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'input_buffer_size' must be smaller or equal to %u.\n", INT_MAX);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (0 >= length)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'length' must be larger than 0.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (length > input_buffer_size - offset)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'length' must be smaller or equal to %i.\n", input_buffer_size - offset);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (sizeof(uint64_t) < length)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Input buffer length remaining from offset must be smaller than %zu.\n", sizeof(uint64_t));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		for (i = 0; i < length; i++)
 | |
| 		{
 | |
| 			tmp = (tmp << 8) + input_buffer[offset + i];
 | |
| 		}
 | |
| 		*output_value = tmp;
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int hexstr_to_bytearray(char *byte_string, uint8_t *byte_values, size_t byte_values_size)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	char hex_byte[3] = {0};		// Temporary buffer for input bytes.
 | |
| 	char* invalidChars = NULL;	// Pointer to target buffer where method stores invalid characters.
 | |
| 	uint32_t i = 0;			// Loop variable.
 | |
| 	uint32_t unStrLen = 0;		// Temporary store for byte string length.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(byte_string);
 | |
| 		NULL_POINTER_CHECK(byte_values);
 | |
| 
 | |
| 		if (0 >= byte_values_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'byte_values_size' must be larger than 0.\n");
 | |
| 		break;
 | |
| 		}
 | |
| 		if (INT_MAX < byte_values_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'byte_values_size' must be smaller or equal to %u.\n", INT_MAX);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		memset(byte_values, 0, byte_values_size);
 | |
| 
 | |
| 		unStrLen = strlen(byte_string);
 | |
| 		if ((unStrLen / HEX_BYTE_STRING_LENGTH + unStrLen % HEX_BYTE_STRING_LENGTH) > (uint32_t)byte_values_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Input character string is too long for output buffer.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Loop "byte-wise" through string
 | |
| 		for (i = 0; i < unStrLen; i += HEX_BYTE_STRING_LENGTH)
 | |
| 		{
 | |
| 			// Split input string into "bytes"
 | |
| 			if (1 == strlen(byte_string + i))
 | |
| 			{
 | |
| 				// Assemble a single digit in the hex byte string.
 | |
| 				hex_byte[0] = byte_string[i];
 | |
| 				hex_byte[1] = '\0';
 | |
| 				hex_byte[2] = '\0';
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				// Assemble a digit pair in the hex byte string.
 | |
| 				hex_byte[0] = byte_string[i];
 | |
| 				hex_byte[1] = byte_string[i + 1];
 | |
| 				hex_byte[2] = '\0';
 | |
| 			}
 | |
| 
 | |
| 			// Convert the hex string to an integer.
 | |
| 			errno = 0;
 | |
| 			byte_values[i / HEX_BYTE_STRING_LENGTH] = (uint8_t)strtoul(hex_byte, &invalidChars, 16);
 | |
| 			if (0 != errno)
 | |
| 			{
 | |
| 				ret_val = errno;
 | |
| 				fprintf(stderr, "Error parsing string.\n");
 | |
| 				break;
 | |
| 			}
 | |
| 			if ('\0' != *invalidChars)
 | |
| 			{
 | |
| 				ret_val = EINVAL;
 | |
| 				fprintf(stderr, "Invalid character(s) '%s' while trying to parse '%s' to a byte array.\n", invalidChars, byte_string);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int int_to_bytearray(uint64_t input, uint32_t input_size, uint8_t *output_byte)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint32_t i;			// For-while-loop counter.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(output_byte);
 | |
| 		if (0 >= input_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'input_size' must be larger than 0.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (sizeof(uint64_t) < input_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'input_size' must be smaller or equal to %zu.\n", sizeof(uint64_t));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		for (i = 0; i < input_size; i++)
 | |
| 		{
 | |
| 			output_byte[i] = input >> ((input_size - 1 - i) * 8);
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int get_random(char *data_length_string, uint8_t *response_buf)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint8_t bytes_requested = 0;	// Amount of random bytes requested by the user.
 | |
| 	size_t byte_string_size = 0;	// Size of user input.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(data_length_string);
 | |
| 		NULL_POINTER_CHECK(response_buf);
 | |
| 
 | |
| 		// Get length of command line input.
 | |
| 		byte_string_size = strlen(data_length_string) / HEX_BYTE_STRING_LENGTH + strlen(data_length_string) % HEX_BYTE_STRING_LENGTH;
 | |
| 		if (1 != byte_string_size)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Convert the command line input string for requested random data length to byte.
 | |
| 		ret_val = hexstr_to_bytearray(data_length_string, &bytes_requested, 1);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		if (32 < bytes_requested || 0 == bytes_requested)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a hex value between 0x01 and 0x20.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Copy command bytes.
 | |
| 		memcpy(response_buf, tpm2_getrandom, sizeof(tpm2_getrandom));
 | |
| 
 | |
| 		// Store amount of requested bytes at the correct byte index in the command byte stream.
 | |
| 		response_buf[sizeof(tpm2_getrandom) - 1] = bytes_requested;
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int create_hash(char *data_string, hash_algo_enum hash_algo, uint8_t *hash_cmd_buf, uint32_t hash_cmd_buf_size)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;		// Return value.
 | |
| 	uint32_t offset = 0;			// Helper offset for generating command request.
 | |
| 	uint16_t data_string_size = 0;		// Size of user input data.
 | |
| 	const uint8_t *tpm_hash_alg = NULL;	// Pointer to hash algorithm identifier.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(data_string);
 | |
| 		NULL_POINTER_CHECK(hash_cmd_buf);
 | |
| 
 | |
| 		if (TPM_REQ_MAX_SIZE < hash_cmd_buf_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'hash_cmd_buf_size' must be smaller or equal to %u.\n", TPM_REQ_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (sizeof(tpm2_hash) > hash_cmd_buf_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'hash_cmd_buf_size' must be at least %zu.\n", sizeof(tpm2_hash));
 | |
| 			break;
 | |
| 		}
 | |
| 		data_string_size = strlen(data_string) / HEX_BYTE_STRING_LENGTH + strlen(data_string) % HEX_BYTE_STRING_LENGTH;
 | |
| 		if (0 == data_string_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. data_string is empty.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (hash_cmd_buf_size - sizeof(tpm2_hash) < data_string_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Input data size must be smaller or equal to %zu.\n", hash_cmd_buf_size - sizeof(tpm2_hash));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		memset(hash_cmd_buf, 0, hash_cmd_buf_size);
 | |
| 
 | |
| 		// Copy basic command bytes.
 | |
| 		memcpy(hash_cmd_buf, tpm2_hash, sizeof(tpm2_hash));
 | |
| 
 | |
| 		// Set hash algorithm, command and data sizes depending on user input option at the correct byte index in the command byte stream.
 | |
| 		if (ALG_SHA1 == hash_algo)
 | |
| 		{
 | |
| 			tpm_hash_alg = sha1_alg;
 | |
| 			printf("\nTPM2_Hash of '%s' with SHA-1:\n", data_string);
 | |
| 		}
 | |
| 		else if (ALG_SHA256 == hash_algo)
 | |
| 		{
 | |
| 			tpm_hash_alg = sha256_alg;
 | |
| 			printf("\nTPM2_Hash of '%s' with SHA-256:\n", data_string);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			tpm_hash_alg = sha384_alg;
 | |
| 			printf("\nTPM2_Hash of '%s' with SHA-384:\n", data_string);
 | |
| 		}
 | |
| 
 | |
| 		offset = TPM_CMD_SIZE_OFFSET;
 | |
| 		ret_val = int_to_bytearray(sizeof(tpm2_hash) + data_string_size, sizeof(uint32_t), hash_cmd_buf + offset);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		offset = TPM_CMD_HEADER_SIZE;
 | |
| 		ret_val = int_to_bytearray(data_string_size, sizeof(data_string_size), hash_cmd_buf + offset);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		offset += sizeof(data_string_size);
 | |
| 
 | |
| 		// Copy hash data to TPM request.
 | |
| 		ret_val = hexstr_to_bytearray(data_string, hash_cmd_buf + offset, hash_cmd_buf_size - offset);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		offset += data_string_size;
 | |
| 
 | |
| 		// Set hash algorithm and hierarchy.
 | |
| 		memcpy(hash_cmd_buf + offset, tpm_hash_alg, sizeof(sha1_alg));
 | |
| 		offset += sizeof(sha1_alg);
 | |
| 		memcpy(hash_cmd_buf + offset, tpm_cc_hash_hierarchy, sizeof(tpm_cc_hash_hierarchy));
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int create_hash_sequence(char *data_string, hash_algo_enum hash_algo, uint8_t *tpm_response_buf, ssize_t *tpm_response_buf_size)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;		// Return value.
 | |
| 	uint16_t data_string_bytes_size = 0;	// Size of user input data string in bytes.
 | |
| 	uint8_t *data_string_bytes = NULL;	// Buffer for user input data string as bytes.
 | |
| 	uint32_t update_request_size = 0;	// Size of user input string.
 | |
| 	uint16_t transfer_bytes = 0;		// Amount of bytes to be transmitted to the TPM.
 | |
| 	uint16_t remaining_bytes = 0;		// Amount of bytes not yet transmitted to the TPM.
 | |
| 	uint32_t offset = 0;			// Helper offset for generating command request.
 | |
| 	uint64_t tpm_rc = TPM_RC_SUCCESS;	// TPM return code.
 | |
| 	uint8_t *update_request = NULL;		// Buffer for update sequence command.
 | |
| 	uint8_t sequence_handle[4];		// Buffer for sequence handle.
 | |
| 	ssize_t original_response_buf_size = 0;	// Backup of the original response buffer size.
 | |
| 	// Minimum success response buffer size (TPM command header + sequence handle)
 | |
| 	ssize_t minimum_response_buf_size = TPM_CMD_HEADER_SIZE + sizeof(sequence_handle);
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(tpm_response_buf);
 | |
| 		NULL_POINTER_CHECK(data_string);
 | |
| 		NULL_POINTER_CHECK(tpm_response_buf_size);
 | |
| 
 | |
| 		memset(tpm_response_buf, 0, *tpm_response_buf_size);
 | |
| 		memset(sequence_handle, 0, 4);
 | |
| 
 | |
| 		if (TPM_RESP_MAX_SIZE < *tpm_response_buf_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter '*tpm_response_buf_size' must be smaller or equal to %u.\n", TPM_RESP_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (minimum_response_buf_size > *tpm_response_buf_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter '*tpm_response_buf_size' must be at least %zu.\n", minimum_response_buf_size);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		original_response_buf_size = *tpm_response_buf_size;
 | |
| 
 | |
| 		// Set hash algorithm depending on user input option at the correct byte index in the command byte stream.
 | |
| 		if (ALG_SHA1 == hash_algo)
 | |
| 		{
 | |
| 			printf("\nTPM2_HashSequenceStart of '%s' with SHA-1:\n", data_string);
 | |
| 			memcpy(tpm2_hash_sequence_start + 12, sha1_alg, sizeof(sha1_alg));
 | |
| 		}
 | |
| 		else if (ALG_SHA256 == hash_algo)
 | |
| 		{
 | |
| 			printf("\nTPM2_HashSequenceStart of '%s' with SHA-256:\n", data_string);
 | |
| 			memcpy(tpm2_hash_sequence_start + 12, sha256_alg, sizeof(sha256_alg));
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			printf("\nTPM2_HashSequenceStart of '%s' with SHA-384:\n", data_string);
 | |
| 			memcpy(tpm2_hash_sequence_start + 12, sha384_alg, sizeof(sha384_alg));
 | |
| 		}
 | |
| 
 | |
| 		// Send the TPM2_HashSequenceStart command to the TPM.
 | |
| 		ret_val = tpmtool_transmit(tpm2_hash_sequence_start, sizeof(tpm2_hash_sequence_start), tpm_response_buf, tpm_response_buf_size);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		// Print the TPM response.
 | |
| 		NULL_POINTER_CHECK(tpm_response_buf_size);
 | |
| 		ret_val = print_response_buf(tpm_response_buf, (size_t)*tpm_response_buf_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		// Abort in case of TPM error.
 | |
| 		ret_val = buf_to_uint64(tpm_response_buf, 6, 4, &tpm_rc, *tpm_response_buf_size);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		if (TPM_RC_SUCCESS != tpm_rc)
 | |
| 		{
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Get sequence handle from TPM response.
 | |
| 		memcpy(sequence_handle, tpm_response_buf + TPM_CMD_HEADER_SIZE, sizeof(sequence_handle));
 | |
| 
 | |
| 		// Calculate byte sizes of hash input string.
 | |
| 		data_string_bytes_size = strlen(data_string) / HEX_BYTE_STRING_LENGTH + strlen(data_string) % HEX_BYTE_STRING_LENGTH;
 | |
| 
 | |
| 		// Allocate memory for conversion of hash input string.
 | |
| 		data_string_bytes = malloc(data_string_bytes_size);
 | |
| 		MALLOC_ERROR_CHECK(data_string_bytes);
 | |
| 		memset(data_string_bytes, 0, data_string_bytes_size);
 | |
| 
 | |
| 		// Convert hash input string to bytes.
 | |
| 		ret_val = hexstr_to_bytearray(data_string, data_string_bytes, data_string_bytes_size);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		// If necessary split input bytes into multiple TPM2_SequenceUpdate commands
 | |
| 		remaining_bytes = data_string_bytes_size;
 | |
| 		while (remaining_bytes > 0)
 | |
| 		{
 | |
| 			// Calculate amount of bytes to be transmitted next
 | |
| 			if (remaining_bytes <= TPM_REQ_MAX_SIZE - sizeof(tpm2_sequence_update))
 | |
| 			{
 | |
| 				transfer_bytes = remaining_bytes;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				transfer_bytes = TPM_REQ_MAX_SIZE - sizeof(tpm2_sequence_update);
 | |
| 			}
 | |
| 			update_request_size = transfer_bytes + sizeof(tpm2_sequence_update);
 | |
| 
 | |
| 			// Compose the TPM2_SequenceUpdate command.
 | |
| 			update_request = malloc(update_request_size);
 | |
| 			MALLOC_ERROR_CHECK(update_request);
 | |
| 			memset(update_request, 0, update_request_size);
 | |
| 			memcpy(update_request, tpm2_sequence_update, sizeof(tpm2_sequence_update));
 | |
| 			offset = TPM_CMD_SIZE_OFFSET;
 | |
| 			ret_val = int_to_bytearray(update_request_size, sizeof(update_request_size), update_request + offset);
 | |
| 			RET_VAL_CHECK(ret_val);
 | |
| 			offset = TPM_CMD_HEADER_SIZE;
 | |
| 			memcpy(update_request + offset, sequence_handle, sizeof(sequence_handle));
 | |
| 			offset = sizeof(tpm2_sequence_update) - sizeof(transfer_bytes);
 | |
| 			ret_val = int_to_bytearray(transfer_bytes, sizeof(transfer_bytes), update_request + offset);
 | |
| 			RET_VAL_CHECK(ret_val);
 | |
| 			memcpy(update_request + sizeof(tpm2_sequence_update), data_string_bytes + data_string_bytes_size - remaining_bytes, transfer_bytes);
 | |
| 
 | |
| 			// Send the TPM2_SequenceUpdate command to the TPM.
 | |
| 			printf("\n\nTPM2_SequenceUpdate:\n");
 | |
| 			*tpm_response_buf_size = original_response_buf_size;
 | |
| 			ret_val = tpmtool_transmit(update_request, update_request_size, tpm_response_buf, tpm_response_buf_size);
 | |
| 			RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 			// Free allocated memory
 | |
| 			MEMSET_FREE(update_request, update_request_size);
 | |
| 
 | |
| 			// Print the TPM response.
 | |
| 			NULL_POINTER_CHECK(tpm_response_buf_size);
 | |
| 			ret_val = print_response_buf(tpm_response_buf, (size_t)*tpm_response_buf_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS);
 | |
| 			RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 			// Abort in case of TPM error.
 | |
| 			ret_val = buf_to_uint64(tpm_response_buf, 6, 4, &tpm_rc, *tpm_response_buf_size);
 | |
| 			RET_VAL_CHECK(ret_val);
 | |
| 			if (TPM_RC_SUCCESS != tpm_rc)
 | |
| 			{
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			remaining_bytes = remaining_bytes - transfer_bytes;
 | |
| 		}
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		if (TPM_RC_SUCCESS != tpm_rc)
 | |
| 		{
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Set the sequence handle in the TPM2_SequenceComplete command.
 | |
| 		memcpy(tpm2_sequence_complete + TPM_CMD_HEADER_SIZE, sequence_handle, sizeof(sequence_handle));
 | |
| 
 | |
| 		// Send the TPM2_SequenceComplete command to the TPM.
 | |
| 		printf("\n\nTPM2_SequenceComplete:\n");
 | |
| 		*tpm_response_buf_size = original_response_buf_size;
 | |
| 		ret_val = tpmtool_transmit(tpm2_sequence_complete, sizeof(tpm2_sequence_complete), tpm_response_buf, tpm_response_buf_size);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		// Print the TPM response.
 | |
| 		NULL_POINTER_CHECK(tpm_response_buf_size);
 | |
| 		ret_val = print_response_buf(tpm_response_buf, (size_t)*tpm_response_buf_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS);
 | |
| 		printf("\n\nHash value extracted from TPM response:\n");
 | |
| 	} while (0);
 | |
| 
 | |
| 	MEMSET_FREE(data_string_bytes, data_string_bytes_size);
 | |
| 	MEMSET_FREE(update_request, update_request_size);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int pcr_extend(char *pcr_index_str, char *pcr_digest_str, uint8_t *pcr_cmd_buf, size_t pcr_cmd_buf_size, hash_algo_enum hash_algo)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint8_t pcr_index = 0;		// PCR index user input byte.
 | |
| 	uint32_t pcr_digest_size = 0;	// Sizeof PCR digest user input.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(pcr_index_str);
 | |
| 		NULL_POINTER_CHECK(pcr_digest_str);
 | |
| 		NULL_POINTER_CHECK(pcr_cmd_buf);
 | |
| 
 | |
| 		if (TPM_REQ_MAX_SIZE < pcr_cmd_buf_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'pcr_cmd_buf_size' size must be smaller or equal to %u.\n", TPM_REQ_MAX_SIZE);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (sizeof(tpm2_pcr_extend) > pcr_cmd_buf_size)
 | |
| 		{
 | |
| 			ret_val = EINVAL;
 | |
| 			fprintf(stderr, "Bad parameter. Value of parameter 'pcr_cmd_buf_size' must be at least %zu.\n", sizeof(tpm2_pcr_extend));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		memset(pcr_cmd_buf, 0, pcr_cmd_buf_size);
 | |
| 
 | |
| 		// Check and convert the command line input (PCR index) to bytes.
 | |
| 		if (1 != strlen(pcr_index_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_index_str) % HEX_BYTE_STRING_LENGTH)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		ret_val = hexstr_to_bytearray(pcr_index_str, &pcr_index, 1);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		if (23 < pcr_index)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a hex value between 0x00 and 0x17 in hex without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Check the command line input (PCR digest).
 | |
| 		pcr_digest_size = strlen(pcr_digest_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_digest_str) % HEX_BYTE_STRING_LENGTH;
 | |
| 		if (ALG_SHA1 == hash_algo && TPM_SHA1_DIGEST_SIZE < pcr_digest_size)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Maximum SHA-1 PCR digest size is 20 byte (40 characters), but you entered %u byte.\n", pcr_digest_size);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (ALG_SHA256 == hash_algo && TPM_SHA256_DIGEST_SIZE < pcr_digest_size)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Maximum SHA-256 PCR digest size is 32 byte (64 characters), but you entered %u byte.\n", pcr_digest_size);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (ALG_SHA384 == hash_algo && TPM_SHA384_DIGEST_SIZE < pcr_digest_size)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Maximum SHA-384 PCR digest size is 48 byte (96 characters), but you entered %u byte.\n", pcr_digest_size);
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Copy basic command bytes.
 | |
| 		memcpy(pcr_cmd_buf, tpm2_pcr_extend, sizeof(tpm2_pcr_extend));
 | |
| 
 | |
| 		// Store PCR index at the correct byte index in the command byte stream.
 | |
| 		pcr_cmd_buf[13] = pcr_index;
 | |
| 
 | |
| 		// Convert the PCR digest to bytes and store it at the correct byte index in the command byte stream.
 | |
| 		ret_val = hexstr_to_bytearray(pcr_digest_str, pcr_cmd_buf + sizeof(tpm2_pcr_extend), pcr_cmd_buf_size - sizeof(tpm2_pcr_extend));
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 
 | |
| 		// Set hash algorithm and command length depending on user input option at the correct byte index in the command byte stream.
 | |
| 		if (ALG_SHA1 == hash_algo)
 | |
| 		{
 | |
| 			pcr_cmd_buf[5] = sizeof(tpm2_pcr_extend) + TPM_SHA1_DIGEST_SIZE;
 | |
| 			memcpy(pcr_cmd_buf + 31, sha1_alg, sizeof(sha1_alg));
 | |
| 			printf("Extend PCR %i (SHA-1) with digest { ", pcr_index);
 | |
| 		}
 | |
| 		else if (ALG_SHA256 == hash_algo)
 | |
| 		{
 | |
| 			pcr_cmd_buf[5] = sizeof(tpm2_pcr_extend) + TPM_SHA256_DIGEST_SIZE;
 | |
| 			memcpy(pcr_cmd_buf + 31, sha256_alg, sizeof(sha256_alg));
 | |
| 			printf("Extend PCR %i (SHA-256) with digest { ", pcr_index);
 | |
| 		}
 | |
| 		else if (ALG_SHA384 == hash_algo)
 | |
| 		{
 | |
| 			pcr_cmd_buf[5] = sizeof(tpm2_pcr_extend) + TPM_SHA384_DIGEST_SIZE;
 | |
| 			memcpy(pcr_cmd_buf + 31, sha384_alg, sizeof(sha384_alg));
 | |
| 			printf("Extend PCR %i (SHA-384) with digest { ", pcr_index);
 | |
| 		}
 | |
| 		print_response_buf(pcr_cmd_buf, pcr_cmd_buf_size, sizeof(tpm2_pcr_extend), PRINT_RESPONSE_CLEAR);
 | |
| 		printf("}:\n");
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int pcr_allocate(uint8_t *pcr_cmd_buf, hash_algo_enum hash_algo)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	unsigned char set[] = {0xFF, 0xFF, 0xFF};
 | |
| 	unsigned char clear[] = {0x00, 0x00, 0x00};
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(pcr_cmd_buf);
 | |
| 
 | |
| 		// Copy basic command bytes.
 | |
| 		memcpy(pcr_cmd_buf, tpm2_pcr_allocate, sizeof(tpm2_pcr_allocate));
 | |
| 
 | |
| 		// Set hash algorithm depending on user input option at the correct byte index in the command byte stream.
 | |
| 		if (ALG_SHA1 == hash_algo)
 | |
| 		{
 | |
| 			memcpy(pcr_cmd_buf + 34, set, sizeof(set));
 | |
| 			memcpy(pcr_cmd_buf + 40, clear, sizeof(clear));
 | |
| 			memcpy(pcr_cmd_buf + 46, clear, sizeof(clear));
 | |
| 			printf("PCR allocate SHA-1 bank\n");
 | |
| 		}
 | |
| 		else if (ALG_SHA256 == hash_algo)
 | |
| 		{
 | |
| 			memcpy(pcr_cmd_buf + 34, clear, sizeof(clear));
 | |
| 			memcpy(pcr_cmd_buf + 40, set, sizeof(set));
 | |
| 			memcpy(pcr_cmd_buf + 46, clear, sizeof(clear));
 | |
| 			printf("PCR allocate SHA-256 bank\n");
 | |
| 		}
 | |
| 		else if (ALG_SHA384 == hash_algo)
 | |
| 		{
 | |
| 			memcpy(pcr_cmd_buf + 34, clear, sizeof(clear));
 | |
| 			memcpy(pcr_cmd_buf + 40, clear, sizeof(clear));
 | |
| 			memcpy(pcr_cmd_buf + 46, set, sizeof(set));
 | |
| 			printf("PCR allocate SHA-384 bank\n");
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int pcr_read(char *pcr_index_str, uint8_t *pcr_cmd_buf, hash_algo_enum hash_algo)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	int pcr_byte_index = 0;		// The location for pcr_select on pcr_cmd_buf.
 | |
| 	uint8_t pcr_select = 0;		// PCR index as mapped bit value.
 | |
| 	uint8_t pcr_index = 0;		// PCR user input byte.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(pcr_index_str);
 | |
| 		NULL_POINTER_CHECK(pcr_cmd_buf);
 | |
| 
 | |
| 		memset(pcr_cmd_buf, 0, 20);
 | |
| 
 | |
| 		// Convert the command line input to bytes.
 | |
| 		if (1 != strlen(pcr_index_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_index_str) % HEX_BYTE_STRING_LENGTH)
 | |
| 		{
 | |
| 			// Current implementation only supports selection of one PCR at a time.
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		ret_val = hexstr_to_bytearray(pcr_index_str, &pcr_index, 1);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		if (23 < pcr_index)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a hex value between 0x00 and 0x17 in hex without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Copy basic command bytes.
 | |
| 		memcpy(pcr_cmd_buf, tpm2_pcr_read, sizeof(tpm2_pcr_read));
 | |
| 
 | |
| 		// Calculate the location of PCR index in command byte stream depends on the PCR index value: 0 for PCRs 0-7, 1 for PCRs 8-15 and 2 for PCRs 16-23.
 | |
| 		pcr_byte_index = pcr_index / 8;
 | |
| 
 | |
| 		// Set corresponding bit in PCR selection byte to 1: bit 0 for PCRs 0, 8 or 16, bit 1 for PCRs 1, 9 or 17, ... (etc.), and bit 7 for PCRs 7, 15 or 23.
 | |
| 		// Note: This would allow to read multiple PCRs at once. For simplicity reasons, ELTT only supports reading one PCR at a time.
 | |
| 		pcr_select = (1 << (pcr_index % 8));
 | |
| 
 | |
| 		// Store pcr_select at the correct byte index in the command byte stream.
 | |
| 		pcr_cmd_buf[17 + pcr_byte_index] = pcr_select;
 | |
| 
 | |
| 		// Set hash algorithm depending on user input option at the correct byte index in the command byte stream.
 | |
| 		if (ALG_SHA1 == hash_algo)
 | |
| 		{
 | |
| 			memcpy(pcr_cmd_buf + 14, sha1_alg, sizeof(sha1_alg));
 | |
| 			printf("Read PCR %i (SHA-1):\n", pcr_index);
 | |
| 		}
 | |
| 		else if (ALG_SHA256 == hash_algo)
 | |
| 		{
 | |
| 			memcpy(pcr_cmd_buf + 14, sha256_alg, sizeof(sha256_alg));
 | |
| 			printf("Read PCR %i (SHA-256):\n", pcr_index);
 | |
| 		}
 | |
| 		else if (ALG_SHA384 == hash_algo)
 | |
| 		{
 | |
| 			memcpy(pcr_cmd_buf + 14, sha384_alg, sizeof(sha384_alg));
 | |
| 			printf("Read PCR %i (SHA-384):\n", pcr_index);
 | |
| 		}
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | |
| 
 | |
| static int pcr_reset(char *pcr_index_str, uint8_t *pcr_cmd_buf)
 | |
| {
 | |
| 	int ret_val = EXIT_SUCCESS;	// Return value.
 | |
| 	uint8_t pcr_index = 0;		// PCR user input byte.
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		NULL_POINTER_CHECK(pcr_index_str);
 | |
| 		NULL_POINTER_CHECK(pcr_cmd_buf);
 | |
| 
 | |
| 		memset(pcr_cmd_buf, 0, 27);
 | |
| 
 | |
| 		// Convert the command line input to bytes.
 | |
| 		if (1 != strlen(pcr_index_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_index_str) % HEX_BYTE_STRING_LENGTH)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 		ret_val = hexstr_to_bytearray(pcr_index_str, &pcr_index, 1);
 | |
| 		RET_VAL_CHECK(ret_val);
 | |
| 		if (23 < pcr_index)
 | |
| 		{
 | |
| 			ret_val = ERR_BAD_CMD;
 | |
| 			fprintf(stderr, "Bad option. Enter a hex value between 0x00 and 0x17 in hex without leading '0x'.\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		// Copy command bytes.
 | |
| 		memcpy(pcr_cmd_buf, tpm2_pcr_reset, sizeof(tpm2_pcr_reset));
 | |
| 
 | |
| 		// Store pcr_index at the correct byte index in the command byte stream.
 | |
| 		pcr_cmd_buf[13] = pcr_index;
 | |
| 
 | |
| 		printf("Reset PCR %i (SHA-1, SHA-256, and SHA-384):\n", pcr_index);
 | |
| 	} while (0);
 | |
| 
 | |
| 	return ret_val;
 | |
| }
 | 
