diff options
| -rw-r--r-- | README | 14 | ||||
| -rw-r--r-- | common/cmd_tpm.c | 100 | ||||
| -rw-r--r-- | include/tpm.h | 174 | ||||
| -rw-r--r-- | lib/tpm.c | 351 | 
4 files changed, 638 insertions, 1 deletions
| @@ -1247,6 +1247,20 @@ The following options need to be configured:  			to. Contemporary x86 systems usually map it at  			0xfed40000. +		CONFIG_CMD_TPM +		Add tpm monitor functions. +		Requires CONFIG_TPM. If CONFIG_TPM_AUTH_SESSIONS is set, also +		provides monitor access to authorized functions. + +		CONFIG_TPM +		Define this to enable the TPM support library which provides +		functional interfaces to some TPM commands. +		Requires support for a TPM device. + +		CONFIG_TPM_AUTH_SESSIONS +		Define this to enable authorized functions in the TPM library. +		Requires CONFIG_TPM and CONFIG_SHA1. +  - USB Support:  		At the moment only the UHCI host controller is  		supported (PIP405, MIP405, MPC5200); define diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c index 46fae1877..c34000a6e 100644 --- a/common/cmd_tpm.c +++ b/common/cmd_tpm.c @@ -27,6 +27,13 @@  #include <asm/unaligned.h>  #include <linux/string.h> +/* Useful constants */ +enum { +	DIGEST_LENGTH		= 20, +	/* max lengths, valid for RSA keys <= 2048 bits */ +	TPM_PUBKEY_MAX_LENGTH	= 288, +}; +  /**   * Print a byte string in hexdecimal format, 16-bytes per line.   * @@ -546,6 +553,72 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag,  	return convert_return_code(err);  } +#ifdef CONFIG_TPM_AUTH_SESSIONS + +static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag, +		int argc, char * const argv[]) +{ +	uint32_t auth_handle, err; + +	err = tpm_oiap(&auth_handle); + +	return convert_return_code(err); +} + +static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag, +		int argc, char * const argv[]) +{ +	uint32_t parent_handle, key_len, key_handle, err; +	uint8_t usage_auth[DIGEST_LENGTH]; +	void *key; + +	if (argc < 5) +		return CMD_RET_USAGE; + +	parent_handle = simple_strtoul(argv[1], NULL, 0); +	key = (void *)simple_strtoul(argv[2], NULL, 0); +	key_len = simple_strtoul(argv[3], NULL, 0); +	if (strlen(argv[4]) != 2 * DIGEST_LENGTH) +		return CMD_RET_FAILURE; +	parse_byte_string(argv[4], usage_auth, NULL); + +	err = tpm_load_key2_oiap(parent_handle, key, key_len, usage_auth, +			&key_handle); +	if (!err) +		printf("Key handle is 0x%x\n", key_handle); + +	return convert_return_code(err); +} + +static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag, +		int argc, char * const argv[]) +{ +	uint32_t key_handle, err; +	uint8_t usage_auth[DIGEST_LENGTH]; +	uint8_t pub_key_buffer[TPM_PUBKEY_MAX_LENGTH]; +	size_t pub_key_len = sizeof(pub_key_buffer); + +	if (argc < 3) +		return CMD_RET_USAGE; + +	key_handle = simple_strtoul(argv[1], NULL, 0); +	if (strlen(argv[2]) != 2 * DIGEST_LENGTH) +		return CMD_RET_FAILURE; +	parse_byte_string(argv[2], usage_auth, NULL); + +	err = tpm_get_pub_key_oiap(key_handle, usage_auth, +			pub_key_buffer, &pub_key_len); +	if (!err) { +		printf("dump of received pub key structure:\n"); +		print_byte_string(pub_key_buffer, pub_key_len); +	} +	return convert_return_code(err); +} + +TPM_COMMAND_NO_ARG(tpm_end_oiap) + +#endif /* CONFIG_TPM_AUTH_SESSIONS */ +  #define MAKE_TPM_CMD_ENTRY(cmd) \  	U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") @@ -590,6 +663,16 @@ static cmd_tbl_t tpm_commands[] = {  			do_tpm_nv_read, "", ""),  	U_BOOT_CMD_MKENT(nv_write, 0, 1,  			do_tpm_nv_write, "", ""), +#ifdef CONFIG_TPM_AUTH_SESSIONS +	U_BOOT_CMD_MKENT(oiap, 0, 1, +			 do_tpm_oiap, "", ""), +	U_BOOT_CMD_MKENT(end_oiap, 0, 1, +			 do_tpm_end_oiap, "", ""), +	U_BOOT_CMD_MKENT(load_key2_oiap, 0, 1, +			 do_tpm_load_key2_oiap, "", ""), +	U_BOOT_CMD_MKENT(get_pub_key_oiap, 0, 1, +			 do_tpm_get_pub_key_oiap, "", ""), +#endif /* CONFIG_TPM_AUTH_SESSIONS */  };  static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -638,6 +721,16 @@ U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,  "  get_capability cap_area sub_cap addr count\n"  "    - Read <count> bytes of TPM capability indexed by <cap_area> and\n"  "      <sub_cap> to memory address <addr>.\n" +#ifdef CONFIG_TPM_AUTH_SESSIONS +"Storage functions\n" +"  loadkey2_oiap parent_handle key_addr key_len usage_auth\n" +"    - loads a key data from memory address <key_addr>, <key_len> bytes\n" +"      into TPM using the parent key <parent_handle> with authorization\n" +"      <usage_auth> (20 bytes hex string).\n" +"  get_pub_key_oiap key_handle usage_auth\n" +"    - get the public key portion of a loaded key <key_handle> using\n" +"      authorization <usage auth> (20 bytes hex string)\n" +#endif /* CONFIG_TPM_AUTH_SESSIONS */  "Endorsement Key Handling Commands:\n"  "  read_pubek addr count\n"  "    - Read <count> bytes of the public endorsement key to memory\n" @@ -648,6 +741,13 @@ U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,  "      <digest_hex_string>\n"  "  pcr_read index addr count\n"  "    - Read <count> bytes from PCR <index> to memory address <addr>.\n" +#ifdef CONFIG_TPM_AUTH_SESSIONS +"Authorization Sessions\n" +"  oiap\n" +"    - setup an OIAP session\n" +"  end_oiap\n" +"    - terminates an active OIAP session\n" +#endif /* CONFIG_TPM_AUTH_SESSIONS */  "Non-volatile Storage Commands:\n"  "  nv_define_space index permission size\n"  "    - Establish a space at index <index> with <permission> of <size> bytes.\n" diff --git a/include/tpm.h b/include/tpm.h index 7219b7319..5e9f83225 100644 --- a/include/tpm.h +++ b/include/tpm.h @@ -1,5 +1,6 @@  /*   * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH   *   * See file CREDITS for list of people who contributed to this   * project. @@ -54,6 +55,120 @@ enum tpm_nv_index {  };  /** + * TPM return codes as defined in the TCG Main specification + * (TPM Main Part 2 Structures; Specification version 1.2) + */ +enum tpm_return_code { +	TPM_BASE	= 0x00000000, +	TPM_NON_FATAL	= 0x00000800, +	TPM_SUCCESS	= TPM_BASE, +	/* TPM-defined fatal error codes */ +	TPM_AUTHFAIL			= TPM_BASE +  1, +	TPM_BADINDEX			= TPM_BASE +  2, +	TPM_BAD_PARAMETER		= TPM_BASE +  3, +	TPM_AUDITFAILURE		= TPM_BASE +  4, +	TPM_CLEAR_DISABLED		= TPM_BASE +  5, +	TPM_DEACTIVATED			= TPM_BASE +  6, +	TPM_DISABLED			= TPM_BASE +  7, +	TPM_DISABLED_CMD		= TPM_BASE +  8, +	TPM_FAIL			= TPM_BASE +  9, +	TPM_BAD_ORDINAL			= TPM_BASE + 10, +	TPM_INSTALL_DISABLED		= TPM_BASE + 11, +	TPM_INVALID_KEYHANDLE		= TPM_BASE + 12, +	TPM_KEYNOTFOUND			= TPM_BASE + 13, +	TPM_INAPPROPRIATE_ENC		= TPM_BASE + 14, +	TPM_MIGRATE_FAIL		= TPM_BASE + 15, +	TPM_INVALID_PCR_INFO		= TPM_BASE + 16, +	TPM_NOSPACE			= TPM_BASE + 17, +	TPM_NOSRK			= TPM_BASE + 18, +	TPM_NOTSEALED_BLOB		= TPM_BASE + 19, +	TPM_OWNER_SET			= TPM_BASE + 20, +	TPM_RESOURCES			= TPM_BASE + 21, +	TPM_SHORTRANDOM			= TPM_BASE + 22, +	TPM_SIZE			= TPM_BASE + 23, +	TPM_WRONGPCRVAL			= TPM_BASE + 24, +	TPM_BAD_PARAM_SIZE		= TPM_BASE + 25, +	TPM_SHA_THREAD			= TPM_BASE + 26, +	TPM_SHA_ERROR			= TPM_BASE + 27, +	TPM_FAILEDSELFTEST		= TPM_BASE + 28, +	TPM_AUTH2FAIL			= TPM_BASE + 29, +	TPM_BADTAG			= TPM_BASE + 30, +	TPM_IOERROR			= TPM_BASE + 31, +	TPM_ENCRYPT_ERROR		= TPM_BASE + 32, +	TPM_DECRYPT_ERROR		= TPM_BASE + 33, +	TPM_INVALID_AUTHHANDLE		= TPM_BASE + 34, +	TPM_NO_ENDORSEMENT		= TPM_BASE + 35, +	TPM_INVALID_KEYUSAGE		= TPM_BASE + 36, +	TPM_WRONG_ENTITYTYPE		= TPM_BASE + 37, +	TPM_INVALID_POSTINIT		= TPM_BASE + 38, +	TPM_INAPPROPRIATE_SIG		= TPM_BASE + 39, +	TPM_BAD_KEY_PROPERTY		= TPM_BASE + 40, +	TPM_BAD_MIGRATION		= TPM_BASE + 41, +	TPM_BAD_SCHEME			= TPM_BASE + 42, +	TPM_BAD_DATASIZE		= TPM_BASE + 43, +	TPM_BAD_MODE			= TPM_BASE + 44, +	TPM_BAD_PRESENCE		= TPM_BASE + 45, +	TPM_BAD_VERSION			= TPM_BASE + 46, +	TPM_NO_WRAP_TRANSPORT		= TPM_BASE + 47, +	TPM_AUDITFAIL_UNSUCCESSFUL	= TPM_BASE + 48, +	TPM_AUDITFAIL_SUCCESSFUL	= TPM_BASE + 49, +	TPM_NOTRESETABLE		= TPM_BASE + 50, +	TPM_NOTLOCAL			= TPM_BASE + 51, +	TPM_BAD_TYPE			= TPM_BASE + 52, +	TPM_INVALID_RESOURCE		= TPM_BASE + 53, +	TPM_NOTFIPS			= TPM_BASE + 54, +	TPM_INVALID_FAMILY		= TPM_BASE + 55, +	TPM_NO_NV_PERMISSION		= TPM_BASE + 56, +	TPM_REQUIRES_SIGN		= TPM_BASE + 57, +	TPM_KEY_NOTSUPPORTED		= TPM_BASE + 58, +	TPM_AUTH_CONFLICT		= TPM_BASE + 59, +	TPM_AREA_LOCKED			= TPM_BASE + 60, +	TPM_BAD_LOCALITY		= TPM_BASE + 61, +	TPM_READ_ONLY			= TPM_BASE + 62, +	TPM_PER_NOWRITE			= TPM_BASE + 63, +	TPM_FAMILY_COUNT		= TPM_BASE + 64, +	TPM_WRITE_LOCKED		= TPM_BASE + 65, +	TPM_BAD_ATTRIBUTES		= TPM_BASE + 66, +	TPM_INVALID_STRUCTURE		= TPM_BASE + 67, +	TPM_KEY_OWNER_CONTROL		= TPM_BASE + 68, +	TPM_BAD_COUNTER			= TPM_BASE + 69, +	TPM_NOT_FULLWRITE		= TPM_BASE + 70, +	TPM_CONTEXT_GAP			= TPM_BASE + 71, +	TPM_MAXNVWRITES			= TPM_BASE + 72, +	TPM_NOOPERATOR			= TPM_BASE + 73, +	TPM_RESOURCEMISSING		= TPM_BASE + 74, +	TPM_DELEGATE_LOCK		= TPM_BASE + 75, +	TPM_DELEGATE_FAMILY		= TPM_BASE + 76, +	TPM_DELEGATE_ADMIN		= TPM_BASE + 77, +	TPM_TRANSPORT_NOTEXCLUSIVE	= TPM_BASE + 78, +	TPM_OWNER_CONTROL		= TPM_BASE + 79, +	TPM_DAA_RESOURCES		= TPM_BASE + 80, +	TPM_DAA_INPUT_DATA0		= TPM_BASE + 81, +	TPM_DAA_INPUT_DATA1		= TPM_BASE + 82, +	TPM_DAA_ISSUER_SETTINGS		= TPM_BASE + 83, +	TPM_DAA_TPM_SETTINGS		= TPM_BASE + 84, +	TPM_DAA_STAGE			= TPM_BASE + 85, +	TPM_DAA_ISSUER_VALIDITY		= TPM_BASE + 86, +	TPM_DAA_WRONG_W			= TPM_BASE + 87, +	TPM_BAD_HANDLE			= TPM_BASE + 88, +	TPM_BAD_DELEGATE		= TPM_BASE + 89, +	TPM_BADCONTEXT			= TPM_BASE + 90, +	TPM_TOOMANYCONTEXTS		= TPM_BASE + 91, +	TPM_MA_TICKET_SIGNATURE		= TPM_BASE + 92, +	TPM_MA_DESTINATION		= TPM_BASE + 93, +	TPM_MA_SOURCE			= TPM_BASE + 94, +	TPM_MA_AUTHORITY		= TPM_BASE + 95, +	TPM_PERMANENTEK			= TPM_BASE + 97, +	TPM_BAD_SIGNATURE		= TPM_BASE + 98, +	TPM_NOCONTEXTSPACE		= TPM_BASE + 99, +	/* TPM-defined non-fatal errors */ +	TPM_RETRY		= TPM_BASE + TPM_NON_FATAL, +	TPM_NEEDS_SELFTEST	= TPM_BASE + TPM_NON_FATAL + 1, +	TPM_DOING_SELFTEST	= TPM_BASE + TPM_NON_FATAL + 2, +	TPM_DEFEND_LOCK_RUNNING	= TPM_BASE + TPM_NON_FATAL + 3, +}; + +/**   * Initialize TPM device.  It must be called before any TPM commands.   *   * @return 0 on success, non-0 on error. @@ -201,4 +316,63 @@ uint32_t tpm_physical_set_deactivated(uint8_t state);  uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,  		void *cap, size_t count); +/** + * Issue a TPM_FlushSpecific command for a AUTH ressource. + * + * @param auth_handle	handle of the auth session + * @return return code of the operation + */ +uint32_t tpm_terminate_auth_session(uint32_t auth_handle); + +/** + * Issue a TPM_OIAP command to setup an object independant authorization + * session. + * Information about the session is stored internally. + * If there was already an OIAP session active it is terminated and a new + * session is set up. + * + * @param auth_handle	pointer to the (new) auth handle or NULL. + * @return return code of the operation + */ +uint32_t tpm_oiap(uint32_t *auth_handle); + +/** + * Ends an active OIAP session. + * + * @return return code of the operation + */ +uint32_t tpm_end_oiap(void); + +/** + * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating + * the usage of the parent key. + * + * @param parent_handle	handle of the parent key. + * @param key		pointer to the key structure (TPM_KEY or TPM_KEY12). + * @param key_length	size of the key structure + * @param parent_key_usage_auth	usage auth for the parent key + * @param key_handle	pointer to the key handle + * @return return code of the operation + */ +uint32_t tpm_load_key2_oiap(uint32_t parent_handle, +		const void *key, size_t key_length, +		const void *parent_key_usage_auth, +		uint32_t *key_handle); + +/** + * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for + * authenticating the usage of the key. + * + * @param key_handle	handle of the key + * @param usage_auth	usage auth for the key + * @param pubkey	pointer to the pub key buffer; may be NULL if the pubkey + *			should not be stored. + * @param pubkey_len	pointer to the pub key buffer len. On entry: the size of + *			the provided pubkey buffer. On successful exit: the size + *			of the stored TPM_PUBKEY structure (iff pubkey != NULL). + * @return return code of the operation + */ +uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, +		void *pubkey, size_t *pubkey_len); +  #endif /* __TPM_H */ @@ -1,5 +1,6 @@  /*   * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH   *   * See file CREDITS for list of people who contributed to this   * project. @@ -22,6 +23,7 @@  #include <common.h>  #include <stdarg.h> +#include <sha1.h>  #include <tpm.h>  #include <asm/unaligned.h> @@ -35,8 +37,31 @@ enum {  	TPM_REQUEST_HEADER_LENGTH	= 10,  	TPM_RESPONSE_HEADER_LENGTH	= 10,  	PCR_DIGEST_LENGTH		= 20, +	DIGEST_LENGTH			= 20, +	TPM_REQUEST_AUTH_LENGTH		= 45, +	TPM_RESPONSE_AUTH_LENGTH	= 41, +	/* some max lengths, valid for RSA keys <= 2048 bits */ +	TPM_KEY12_MAX_LENGTH		= 618, +	TPM_PUBKEY_MAX_LENGTH		= 288,  }; +#ifdef CONFIG_TPM_AUTH_SESSIONS + +#ifndef CONFIG_SHA1 +#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too" +#endif /* !CONFIG_SHA1 */ + +struct session_data { +	int		valid; +	uint32_t	handle; +	uint8_t		nonce_even[DIGEST_LENGTH]; +	uint8_t		nonce_odd[DIGEST_LENGTH]; +}; + +static struct session_data oiap_session = {0, }; + +#endif /* CONFIG_TPM_AUTH_SESSIONS */ +  /**   * Pack data into a byte string.  The data types are specified in   * the format string: 'b' means unsigned byte, 'w' unsigned word, @@ -235,7 +260,7 @@ static uint32_t tpm_sendrecv_command(const void *command,  			response, &response_length);  	if (err)  		return TPM_LIB_ERROR; -	if (response) +	if (size_ptr)  		*size_ptr = response_length;  	return tpm_return_code(response); @@ -579,3 +604,327 @@ uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,  	return 0;  } + +#ifdef CONFIG_TPM_AUTH_SESSIONS + +/** + * Fill an authentication block in a request. + * This func can create the first as well as the second auth block (for + * double authorized commands). + * + * @param request	pointer to the request (w/ uninitialised auth data) + * @param request_len0	length of the request without auth data + * @param handles_len	length of the handles area in request + * @param auth_session	pointer to the (valid) auth session to be used + * @param request_auth	pointer to the auth block of the request to be filled + * @param auth		authentication data (HMAC key) + */ +static uint32_t create_request_auth(const void *request, size_t request_len0, +	size_t handles_len, +	struct session_data *auth_session, +	void *request_auth, const void *auth) +{ +	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; +	sha1_context hash_ctx; +	const size_t command_code_offset = 6; +	const size_t auth_nonce_odd_offset = 4; +	const size_t auth_continue_offset = 24; +	const size_t auth_auth_offset = 25; + +	if (!auth_session || !auth_session->valid) +		return TPM_LIB_ERROR; + +	sha1_starts(&hash_ctx); +	sha1_update(&hash_ctx, request + command_code_offset, 4); +	if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len) +		sha1_update(&hash_ctx, +			    request + TPM_REQUEST_HEADER_LENGTH + handles_len, +			    request_len0 - TPM_REQUEST_HEADER_LENGTH +			    - handles_len); +	sha1_finish(&hash_ctx, hmac_data); + +	sha1_starts(&hash_ctx); +	sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH); +	sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data)); +	sha1_finish(&hash_ctx, auth_session->nonce_odd); + +	if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb", +			     0, auth_session->handle, +			     auth_nonce_odd_offset, auth_session->nonce_odd, +			     DIGEST_LENGTH, +			     auth_continue_offset, 1)) +		return TPM_LIB_ERROR; +	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss", +			     DIGEST_LENGTH, +			     auth_session->nonce_even, +			     DIGEST_LENGTH, +			     2 * DIGEST_LENGTH, +			     request_auth + auth_nonce_odd_offset, +			     DIGEST_LENGTH + 1)) +		return TPM_LIB_ERROR; +	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), +		  request_auth + auth_auth_offset); + +	return TPM_SUCCESS; +} + +/** + * Verify an authentication block in a response. + * Since this func updates the nonce_even in the session data it has to be + * called when receiving a succesfull AUTH response. + * This func can verify the first as well as the second auth block (for + * double authorized commands). + * + * @param command_code	command code of the request + * @param response	pointer to the request (w/ uninitialised auth data) + * @param handles_len	length of the handles area in response + * @param auth_session	pointer to the (valid) auth session to be used + * @param response_auth	pointer to the auth block of the response to be verified + * @param auth		authentication data (HMAC key) + */ +static uint32_t verify_response_auth(uint32_t command_code, +	const void *response, size_t response_len0, +	size_t handles_len, +	struct session_data *auth_session, +	const void *response_auth, const void *auth) +{ +	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; +	uint8_t computed_auth[DIGEST_LENGTH]; +	sha1_context hash_ctx; +	const size_t return_code_offset = 6; +	const size_t auth_continue_offset = 20; +	const size_t auth_auth_offset = 21; +	uint8_t auth_continue; + +	if (!auth_session || !auth_session->valid) +		return TPM_AUTHFAIL; +	if (pack_byte_string(hmac_data, sizeof(hmac_data), "d", +			     0, command_code)) +		return TPM_LIB_ERROR; +	if (response_len0 < TPM_RESPONSE_HEADER_LENGTH) +		return TPM_LIB_ERROR; + +	sha1_starts(&hash_ctx); +	sha1_update(&hash_ctx, response + return_code_offset, 4); +	sha1_update(&hash_ctx, hmac_data, 4); +	if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len) +		sha1_update(&hash_ctx, +			    response + TPM_RESPONSE_HEADER_LENGTH + handles_len, +			    response_len0 - TPM_RESPONSE_HEADER_LENGTH +			    - handles_len); +	sha1_finish(&hash_ctx, hmac_data); + +	memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH); +	auth_continue = ((uint8_t *)response_auth)[auth_continue_offset]; +	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", +			     DIGEST_LENGTH, +			     response_auth, +			     DIGEST_LENGTH, +			     2 * DIGEST_LENGTH, +			     auth_session->nonce_odd, +			     DIGEST_LENGTH, +			     3 * DIGEST_LENGTH, +			     auth_continue)) +		return TPM_LIB_ERROR; + +	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), +		  computed_auth); + +	if (memcmp(computed_auth, response_auth + auth_auth_offset, +		   DIGEST_LENGTH)) +		return TPM_AUTHFAIL; + +	return TPM_SUCCESS; +} + + +uint32_t tpm_terminate_auth_session(uint32_t auth_handle) +{ +	const uint8_t command[18] = { +		0x00, 0xc1,		/* TPM_TAG */ +		0x00, 0x00, 0x00, 0x00,	/* parameter size */ +		0x00, 0x00, 0x00, 0xba,	/* TPM_COMMAND_CODE */ +		0x00, 0x00, 0x00, 0x00,	/* TPM_HANDLE */ +		0x00, 0x00, 0x00, 0x02,	/* TPM_RESSOURCE_TYPE */ +	}; +	const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH; +	uint8_t request[COMMAND_BUFFER_SIZE]; + +	if (pack_byte_string(request, sizeof(request), "sd", +			     0, command, sizeof(command), +			     req_handle_offset, auth_handle)) +		return TPM_LIB_ERROR; +	if (oiap_session.valid && oiap_session.handle == auth_handle) +		oiap_session.valid = 0; + +	return tpm_sendrecv_command(request, NULL, NULL); +} + +uint32_t tpm_end_oiap(void) +{ +	uint32_t err = TPM_SUCCESS; +	if (oiap_session.valid) +		err = tpm_terminate_auth_session(oiap_session.handle); +	return err; +} + +uint32_t tpm_oiap(uint32_t *auth_handle) +{ +	const uint8_t command[10] = { +		0x00, 0xc1,		/* TPM_TAG */ +		0x00, 0x00, 0x00, 0x0a,	/* parameter size */ +		0x00, 0x00, 0x00, 0x0a,	/* TPM_COMMAND_CODE */ +	}; +	const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH; +	const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4; +	uint8_t response[COMMAND_BUFFER_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t err; + +	if (oiap_session.valid) +		tpm_terminate_auth_session(oiap_session.handle); + +	err = tpm_sendrecv_command(command, response, &response_length); +	if (err) +		return err; +	if (unpack_byte_string(response, response_length, "ds", +			       res_auth_handle_offset, &oiap_session.handle, +			       res_nonce_even_offset, &oiap_session.nonce_even, +			       (uint32_t)DIGEST_LENGTH)) +		return TPM_LIB_ERROR; +	oiap_session.valid = 1; +	if (auth_handle) +		*auth_handle = oiap_session.handle; +	return 0; +} + +uint32_t tpm_load_key2_oiap(uint32_t parent_handle, +		const void *key, size_t key_length, +		const void *parent_key_usage_auth, +		uint32_t *key_handle) +{ +	const uint8_t command[14] = { +		0x00, 0xc2,		/* TPM_TAG */ +		0x00, 0x00, 0x00, 0x00,	/* parameter size */ +		0x00, 0x00, 0x00, 0x41,	/* TPM_COMMAND_CODE */ +		0x00, 0x00, 0x00, 0x00,	/* parent handle */ +	}; +	const size_t req_size_offset = 2; +	const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH; +	const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4; +	const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH; +	uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH +			+ TPM_REQUEST_AUTH_LENGTH]; +	uint8_t response[COMMAND_BUFFER_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t err; + +	if (!oiap_session.valid) { +		err = tpm_oiap(NULL); +		if (err) +			return err; +	} +	if (pack_byte_string(request, sizeof(request), "sdds", +			     0, command, sizeof(command), +			     req_size_offset, +			     sizeof(command) + key_length +			     + TPM_REQUEST_AUTH_LENGTH, +			     req_parent_handle_offset, parent_handle, +			     req_key_offset, key, key_length +		)) +		return TPM_LIB_ERROR; + +	err = create_request_auth(request, sizeof(command) + key_length, 4, +				&oiap_session, +				request + sizeof(command) + key_length, +				parent_key_usage_auth); +	if (err) +		return err; +	err = tpm_sendrecv_command(request, response, &response_length); +	if (err) { +		if (err == TPM_AUTHFAIL) +			oiap_session.valid = 0; +		return err; +	} + +	err = verify_response_auth(0x00000041, response, +			response_length - TPM_RESPONSE_AUTH_LENGTH, +			4, &oiap_session, +			response + response_length - TPM_RESPONSE_AUTH_LENGTH, +			parent_key_usage_auth); +	if (err) +		return err; + +	if (key_handle) { +		if (unpack_byte_string(response, response_length, "d", +				       res_handle_offset, key_handle)) +			return TPM_LIB_ERROR; +	} + +	return 0; +} + +uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, +			void *pubkey, size_t *pubkey_len) +{ +	const uint8_t command[14] = { +		0x00, 0xc2,		/* TPM_TAG */ +		0x00, 0x00, 0x00, 0x00,	/* parameter size */ +		0x00, 0x00, 0x00, 0x21,	/* TPM_COMMAND_CODE */ +		0x00, 0x00, 0x00, 0x00,	/* key handle */ +	}; +	const size_t req_size_offset = 2; +	const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH; +	const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH; +	uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; +	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +			+ TPM_RESPONSE_AUTH_LENGTH]; +	size_t response_length = sizeof(response); +	uint32_t err; + +	if (!oiap_session.valid) { +		err = tpm_oiap(NULL); +		if (err) +			return err; +	} +	if (pack_byte_string(request, sizeof(request), "sdd", +			     0, command, sizeof(command), +			     req_size_offset, +			     (uint32_t)(sizeof(command) +			     + TPM_REQUEST_AUTH_LENGTH), +			     req_key_handle_offset, key_handle +		)) +		return TPM_LIB_ERROR; +	err = create_request_auth(request, sizeof(command), 4, &oiap_session, +			request + sizeof(command), usage_auth); +	if (err) +		return err; +	err = tpm_sendrecv_command(request, response, &response_length); +	if (err) { +		if (err == TPM_AUTHFAIL) +			oiap_session.valid = 0; +		return err; +	} +	err = verify_response_auth(0x00000021, response, +			response_length - TPM_RESPONSE_AUTH_LENGTH, +			0, &oiap_session, +			response + response_length - TPM_RESPONSE_AUTH_LENGTH, +			usage_auth); +	if (err) +		return err; + +	if (pubkey) { +		if ((response_length - TPM_RESPONSE_HEADER_LENGTH +			- TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) +			return TPM_LIB_ERROR; +		*pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH +			- TPM_RESPONSE_AUTH_LENGTH; +		memcpy(pubkey, response + res_pubkey_offset, +		       response_length - TPM_RESPONSE_HEADER_LENGTH +		       - TPM_RESPONSE_AUTH_LENGTH); +	} + +	return 0; +} + +#endif /* CONFIG_TPM_AUTH_SESSIONS */ |